Reputation: 79
Can someone explain to me why this code
dataGridView1.Rows[0].HeaderCell.Value = 10;
shows nothing while this one
dataGridView1.Rows[0].HeaderCell.Value = 10.ToString();
works correctly?
Upvotes: 3
Views: 358
Reputation: 32278
This looks like a sort of bug. It's actually not, but it feels like one when you set the property and you have different results in similar conditions.
What happens:
[DataGridView].Rows[N].HeaderCell
is of type DataGridViewRowHeaderCell. The FormattedValue
property doesn't belong to this class directly, it's derived from DataGridViewHeaderCell which, in turn, derives it from DataGridViewCell (the generic class).
The DataGridViewHeaderCell
sets the default FormattedValue
and Value
types as:
private static Type defaultFormattedValueType = typeof(System.String);
private static Type defaultValueType = typeof(System.Object);
When we set:
[DataGridView].Rows[N].HeaderCell.Value = 10;
The Value is stored as an Object, boxing an int
.
If we inspect the HeaderCell
object right after setting the Value, we can see that the FormattedValue
and FormattedValueType
properties are set, respectively, to "10"
and System.String
.
This happens because these properties values are retrieved by the DataGridViewCell
class, calling its GetFormattedValue() method.
The FormattedValueType
property defaults to System.String
.
So, it looks like this FormattedValue
will be used when the Header content is rendered.
This doesn't happen. When the Header needs to be rendered, the DataGridViewRowHeaderCell
sets its FormattedValue
to the original Value (an int
): the FormattedValueType
is ignored. The reason is explained, in comments, in the GetContentBounds() method (and in more than one other places):
Intentionally not using GetFormattedValue because header cells don't typically perform formatting.
The content bounds are computed on demand [...]
For the same reason, the Row Header cell doesn't raise CellFormatting
events.
The private PaintPrivate() method, which renders the Row Header cell, receives a formattedValue
representing an int
, not a string.
It then uses:
string formattedString = formattedValue as string;
to convert formattedValue
to a string. Since formattedValue
is not a string, the cast returns null
, so no content is rendered.
The same condition, of course, applies to the DataGridViewCellPaintingEventArgs: when the CellPainting
event is raised, the e.FormattedValue
property returns 10
(an int
).
It return "10"
instead, if we set:
[DataGridView].Rows[N].HeaderCell.Value = "10"; // Or 10.ToString()
In this case, string formattedString = formattedValue as string;
does return a string and this content is rendered.
Now that it's rendered, we can better understand why we cannot use the RowHeader Cell value to display content in this type of Cell: the content bounds are not exactly considered and the rendering is miserable.
To number the Rows using the Row Header, we need to handle the CellPainting event.
Upvotes: 3