Reputation: 615
Does C# allow you to add a String to a RowHeader in a DataGridView? If so, how is it accomplished?
I'm writing a Windows Form to displayed Customer Payment Data for the year so far.
The ColumnHeaders display January, February, March, etc... and rather than have a blank column with DateTime.Now.Year I would like to put it in the RowHeader to make it stand out from the actual payment data.
Upvotes: 28
Views: 188643
Reputation: 5256
Like the OnCellToolTipTextNeeded(...)
and OnRowErrorTextNeeded(...);
built-in methods, there should have been an OnRowHeaderCellValueNeeded(...);
method but there isn't one.
There are two protected methods OnRowErrorTextNeeded(...)
or OnRowPrePaint(...)
that look promising, however there are side-effects trying to use them, i.e. "rowIndex out of bounds". Also, if DoubleBuffered
is false then the result is the process crashes.
The method that seems to behave without side-effects is the OnCellErrorTextNeeded(...)
method. Looking at the stack trace, that method is called inside of a private PaintWork(...)
method, whereas the OnRowErrorTextNeeded(...)
method is not.
Also, one requirement seems to be that the row header cell value must be a String
object, or it is not drawn.
public class MyDGV : DataGridView {
// only set the HeaderCell.Value if the row is different than before
private int onCellErrorTextNeededRowIndexPrevious = -1;
public MyDGV() {
this.Dock = DockStyle.Fill;
this.AllowUserToAddRows = false;
this.AllowUserToResizeRows = false;
this.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.DisplayedCells;
this.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.None;
this.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.AutoSizeToDisplayedHeaders;
this.ColumnHeadersDefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
this.DoubleBuffered = true;
DataTable dt = new DataTable();
dt.Columns.Add("A");
dt.Columns.Add("B", typeof(DateTime));
dt.Columns.Add("C", typeof(int));
int x = 1;
DateTime date = DateTime.Today.AddDays(-52);
for (char c = 'A'; c <= 'Z'; c++) {
dt.Rows.Add(c.ToString().ToLower(), date, x++);
dt.Rows.Add(c.ToString(), date, x++);
date = date.AddDays(1);
}
this.DataSource = dt;
}
protected override void OnCellErrorTextNeeded(DataGridViewCellErrorTextNeededEventArgs e) {
base.OnCellErrorTextNeeded(e);
e.ErrorText = "Cell(" + e.ColumnIndex + ", " + e.RowIndex + ")";
if (e.RowIndex != onCellErrorTextNeededRowIndexPrevious) {
onCellErrorTextNeededRowIndexPrevious = e.RowIndex;
DataGridViewRow rs = this.Rows[e.RowIndex]; // HeaderCell requires unshared row
rs.HeaderCell.Value = (e.RowIndex + 1).ToString();
//Debug.WriteLine("getting: " + e.ErrorText); // testing only
}
else {
//Debug.WriteLine("skipping"); // testing only
}
}
protected override void OnRowErrorTextNeeded(DataGridViewRowErrorTextNeededEventArgs e) {
base.OnRowErrorTextNeeded(e);
e.ErrorText = "Cell(-1, " + e.RowIndex + ")";
}
}
Upvotes: 0
Reputation: 321
private void dtgworkingdays_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
this.FillRecordNo();
}
private void FillRecordNo()
{
for (int i = 0; i < this.dtworkingdays.Rows.Count; i++)
{
this.dtgworkingdays.Rows[i].HeaderCell.Value = (i + 1).ToString();
}
}
Also see Show row number in row header of a DataGridView.
Upvotes: 32
Reputation: 31
I had the same problem, but I noticed that my datagrid lost the rows's header after the datagrid.visible
property changed.
Try to update the rows's headers with the Datagrid.visiblechanged
event.
Upvotes: 3
Reputation: 360
foreach (DataGridViewRow row in datagrid.Rows)
row.HeaderCell.Value = String.Format("{0}", row.Index + 1);
Upvotes: 1
Reputation: 21
I had the same(?) problem. Couldn't get header column to display row header data (a simple row number) with my data bound grid. Once I moved the code to the event "DataBindingComplete" it worked.
Sorry for the extra code. I wanted to provide a working example but don't have time to cut it all down so just cut and pasted some of my app and fixed it up to run for you. Here you go:
using System;
using System.Collections.Generic;
using System.Data;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
namespace WindowsFormsApplication3
{
public partial class Form1 : Form
{
private List<DataPoint> pts = new List<DataPoint>();
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
InsertPoint(10, 20);
InsertPoint(12, 40);
InsertPoint(16, 60);
InsertPoint(20, 77);
InsertPoint(92, 80);
MakeGrid();
}
public void InsertPoint(int parameterValue, int commandValue)
{
DataPoint pt = new DataPoint();
pt.XValue = commandValue;
pt.YValues[0] = parameterValue;
pts.Add(pt);
}
private void MakeGrid()
{
dgv1.SuspendLayout();
DataTable dt = new DataTable();
dt.Columns.Clear();
dt.Columns.Add("Parameter");
dt.Columns.Add("Command");
//*** Add Data to DataTable
for (int i = 0; i <= pts.Count - 1; i++)
{
dt.Rows.Add(pts[i].XValue, pts[i].YValues[0]);
}
dgv1.DataSource = dt;
//*** Formatting for the grid is performed in event dgv1_DataBindingComplete.
//*** If its performed here, the changes appear to get wiped in the grid control.
}
private void dgv1_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
DataGridViewCellStyle style = new DataGridViewCellStyle();
style.Alignment = DataGridViewContentAlignment.MiddleRight;
//*** Add row number to each row
foreach (DataGridViewRow row in dgv1.Rows)
{
row.HeaderCell.Value = (row.Index + 1).ToString();
row.HeaderCell.Style = style;
row.Resizable = DataGridViewTriState.False;
}
dgv1.ClearSelection();
dgv1.CurrentCell = null;
dgv1.ResumeLayout();
}
}
}
Upvotes: 2
Reputation: 1
Here's a little "coup de pouce"
Public Class DataGridViewRHEx
Inherits DataGridView
Protected Overrides Function CreateRowsInstance() As System.Windows.Forms.DataGridViewRowCollection
Dim dgvRowCollec As DataGridViewRowCollection = MyBase.CreateRowsInstance()
AddHandler dgvRowCollec.CollectionChanged, AddressOf dvgRCChanged
Return dgvRowCollec
End Function
Private Sub dvgRCChanged(sender As Object, e As System.ComponentModel.CollectionChangeEventArgs)
If e.Action = System.ComponentModel.CollectionChangeAction.Add Then
Dim dgvRow As DataGridViewRow = e.Element
dgvRow.DefaultHeaderCellType = GetType(DataGridViewRowHeaderCellEx)
End If
End Sub
End Class
Public Class DataGridViewRowHeaderCellEx
Inherits DataGridViewRowHeaderCell
Protected Overrides Sub Paint(graphics As System.Drawing.Graphics, clipBounds As System.Drawing.Rectangle, cellBounds As System.Drawing.Rectangle, rowIndex As Integer, dataGridViewElementState As System.Windows.Forms.DataGridViewElementStates, value As Object, formattedValue As Object, errorText As String, cellStyle As System.Windows.Forms.DataGridViewCellStyle, advancedBorderStyle As System.Windows.Forms.DataGridViewAdvancedBorderStyle, paintParts As System.Windows.Forms.DataGridViewPaintParts)
If Not Me.OwningRow.DataBoundItem Is Nothing Then
If TypeOf Me.OwningRow.DataBoundItem Is DataRowView Then
End If
End If
'HERE YOU CAN USE DATAGRIDROW TAG TO PAINT STRING
formattedValue = CStr(Me.DataGridView.Rows(rowIndex).Tag)
MyBase.Paint(graphics, clipBounds, cellBounds, rowIndex, dataGridViewElementState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts)
End Sub
End Class
Upvotes: 0
Reputation: 35
I think it should be:
dataGridView1.Columns[0].HeaderCell.Value = "my text";
Upvotes: 1
Reputation: 3471
it's because of your first column (Rows Header column) width ! increase it's width then you can see it's value ! you can use this command:
dgv1.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders;
(notice: you must first set dgv1.RowHeadersVisible = true;
)
Upvotes: 5
Reputation: 20747
You don't have to use the RowValidated event, that's just the one I used for a little test app to make sure this worked, but this will set the row (not column) header text to whatever year you specify.
It would probably go better in the CellFormatting event, actually.
private void dataGridView_RowValidated(object sender, DataGridViewCellEventArgs e)
{
DataGridView gridView = sender as DataGridView;
if (null != gridView)
{
gridView.Rows[e.RowIndex].HeaderCell.Value = "2009";
}
}
EDIT: Here's the entire TestForm I used, as simple as possible to demonstrate the solution. Make sure your RowHeadersWidth is wide enough to display the text.
#region
using System.ComponentModel;
using System.Windows.Forms;
#endregion
namespace DataGridViewTest
{
public class GridTest : Form
{
/// <summary>
/// Required designer variable.
/// </summary>
private IContainer components;
private DataGridView dataGridView1;
private DataGridViewTextBoxColumn Month;
public GridTest()
{
InitializeComponent();
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
private void dataGridView_RowValidated(object sender, DataGridViewCellEventArgs e)
{
DataGridView gridView = sender as DataGridView;
if (null != gridView)
{
gridView.Rows[e.RowIndex].HeaderCell.Value = "2009";
}
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.dataGridView1 = new System.Windows.Forms.DataGridView();
this.Month = new System.Windows.Forms.DataGridViewTextBoxColumn();
((System.ComponentModel.ISupportInitialize) (this.dataGridView1)).BeginInit();
this.SuspendLayout();
//
// dataGridView1
//
this.dataGridView1.AutoSizeColumnsMode = System.Windows.Forms.DataGridViewAutoSizeColumnsMode.Fill;
this.dataGridView1.ColumnHeadersHeightSizeMode =
System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.dataGridView1.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[]
{
this.Month
});
this.dataGridView1.Dock = System.Windows.Forms.DockStyle.Fill;
this.dataGridView1.Location = new System.Drawing.Point(0, 0);
this.dataGridView1.Name = "dataGridView1";
this.dataGridView1.RowHeadersWidth = 100;
this.dataGridView1.Size = new System.Drawing.Size(745, 532);
this.dataGridView1.TabIndex = 0;
this.dataGridView1.RowValidated +=
new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView_RowValidated);
//
// Month
//
this.Month.HeaderText = "Month";
this.Month.Name = "Month";
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(745, 532);
this.Controls.Add(this.dataGridView1);
this.Name = "Form1";
this.Text = "Form1";
((System.ComponentModel.ISupportInitialize) (this.dataGridView1)).EndInit();
this.ResumeLayout(false);
}
#endregion
}
}
Upvotes: 9
Reputation: 103742
Yes. First, hook into the column added event:
this.dataGridView1.ColumnAdded += new DataGridViewColumnEventHandler(dataGridView1_ColumnAdded);
Then, in your event handler, just append the text you want to:
private void dataGridView1_ColumnAdded(object sender, DataGridViewColumnEventArgs e)
{
e.Column.HeaderText += additionalHeaderText;
}
Upvotes: -2