I bumped into a question on StackOverflow this evening that I felt might make a short post. Accompanying code is available at my Github repo.
The guy who posted observed that the standard .net DataGridview control provides a helpful little glyph next to the row which contains the active cell:
The original poster of the question was wondering how he might include a similar glyph to indicate the active column as well. My problem with that is that there already exists an option for an arrow-like glyph in a column header. Unfortunately, THAT glyph, by convention, tends to mean “Click here to sort on this column.”
That does NOT mean that the OP was off-base, though. I can think of many cases where it would be handy to have some sort of reference to the active column in addition to the active row.
Emphasize the Active Column with the DataGridViewColumn.HeaderCell.Style property
One way to approach this is to simply cause the text in the header cell to be bold when the user navigates to a cell within that column. We can create a class which inherits from DataGridView
, and take advantage of the CellEnter
Event to cause this to happen:
In the following code, we have a member variable which holds a reference to the last active column. In our constructor, we initialize this column object so that when the control is instantiated, the reference is not null.
We also add an event handler to catch the CellEnter event locally. When this event fires, the handler (dgvControl_CellEnter
) catches it, and makes a call to our final method, OnColumnFocus
. This method accepts a column index as a parameter, and uses the index to identify the new active column. From there, we can use the HeaderCell.Style
property to set the font to “bold” for this particular column.
In our constructor, note that we have to make an initial call to the OnColumnFocus
method, so that the default starting column will be highlighted when the control is displayed at first. However, we have to check to see if there are actually any columns present first. This is because the Visual Studio Designer needs to be able to draw the empty control when we first place it on a form.
DataGridView: Cause the Active Column Header to Display Bold Text
class dgvControl : DataGridView { // hold a reference to the last active column: private DataGridViewColumn _currentColumn; public dgvControl() : base() { // Add a handler for the cell enter event: this.CellEnter += new DataGridViewCellEventHandler(dgvControl_CellEnter); // When the Control is initialized, instantiate the placeholder // variable as a new object: _currentColumn = new DataGridViewColumn(); // In case there are no columns added (for the designer): if (this.Columns.Count > 0) { this.OnColumnFocus(0); } } void dgvControl_CellEnter(object sender, DataGridViewCellEventArgs e) { this.OnColumnFocus(e.ColumnIndex); } void OnColumnFocus(int ColumnIndex) { // If the new cell is in the same column, do nothing: if (ColumnIndex != _currentColumn.Index) { // Set up a custom font to represent the current column: Font selectedFont = new Font(this.Font, FontStyle.Bold); // Grab a reference to the current column: var newColumn = this.Columns[ColumnIndex]; // Change the font to indicate status: newColumn.HeaderCell.Style.Font = selectedFont; // Set the font of the previous column back to normal: _currentColumn.HeaderCell.Style.Font = this.Font; // Set the current column placeholder to refer to the new column: _currentColumn = newColumn; } } }
What if I want More?
What if we want more than just bold text in the active header? Well, things get trickier. Manipulating the other properties of the HeaderCell Style require setting EnableHeaderVisualStyles to false
. This has the unfortunate side effect of flattening out the styling which some from the Windows 7 GUI styles. The slight gradient and color scheme are replaced by a much flatter header. While we could work around this by overriding the OnPaint method (at least to a degree) and implementing our own painting scheme, the impact of the effect is not too disturbing.
For example, we could decide that in addition to bolding the text in the header, we will set the BackColor to a slightly darker gray:
To do this, we need only add three lines of code. First off, in our constructor, we set the EnableHeaderVisualStyles
property to false.
Next, in our OnColumnFocus
method, we set the Style.BackColor
property of the new active column to a darker shade of gray, and restore the previous active column to the default (empty) backcolor:
DataGridView: Cause the Active Column Header to Display Bold Text with a Darker Back Color:
class dgvControl : DataGridView { // hold a reference to the last active column: private DataGridViewColumn _currentColumn; public dgvControl() : base() { this.EnableHeadersVisualStyles = false; // Add a handler for the cell enter event: this.CellEnter += new DataGridViewCellEventHandler(dgvControl_CellEnter); // When the Control is initialized, instantiate the placeholder // variable as a new object: _currentColumn = new DataGridViewColumn(); // In case there are no columns added (for the designer): if (this.Columns.Count > 0) { this.OnColumnFocus(0); } } void dgvControl_CellEnter(object sender, DataGridViewCellEventArgs e) { this.OnColumnFocus(e.ColumnIndex); } void OnColumnFocus(int ColumnIndex) { // If the new cell is in the same column, do nothing: if (ColumnIndex != _currentColumn.Index) { // Set up a custom font to represent the current column: Font selectedFont = new Font(this.Font, FontStyle.Bold); // Grab a reference to the current column: var newColumn = this.Columns[ColumnIndex]; // Change the font to indicate status: newColumn.HeaderCell.Style.Font = selectedFont; // Change the color to a slightly darker shade of gray: newColumn.HeaderCell.Style.BackColor = Color.LightGray; // Set the font of the previous column back to normal: _currentColumn.HeaderCell.Style.Font = this.Font; // Change the color of the previous column back to the default: _currentColumn.HeaderCell.Style.BackColor = Color.Empty; // Set the current column placeholder to refer to the new column: _currentColumn = newColumn; } } }
There are other options you might explore. In this post, we walked through some very basic ways to provide visual feedback to the user about their location within the DataGridView control.
The source code for this post is available at my Github repo.
Comments