How can we improve the DataGridView in our Windows Forms application? It might have some usability or aesthetic problems, or just be hard to deal with, and we would like to explore DataGridView usage and enhancements.
Here are some ways you can improve the DataGridView in your application. You have to use a little discipline to master this, but once you do, your effort will be worth it. There are many resources on this topic, but there are large voids.
Assign it to a collection or database object. It's far more efficient to use the DataSource property to hook your DataGridView up to a database, or even an object collection. I will show you the code, but I will go a step further and show some surrounding code.
/// <summary>
/// Used to set up the data table when the user types a query.
/// </summary>
private void BuildDataGrid()
{
dataGridView1.DataSource = GetSearchResults(queryStr);
}
/// <summary>
/// Connect to the database and then use an adapter to
/// fill a DataTable.
/// </summary>
/// <param name="queryStr">The query supplied by the user.</param>
/// <returns>The results in a table..</returns>
private DataTable GetSearchResults(string queryStr)
{
// Make a new Data Table.
DataTable table = new DataTable();
// You will want to declare a new DataAdapter, and then call its fill method
// on the DataTable.
return table;
}
DataAdapter (SqlDataAdapter) uses internal logic to take data from a database and into an object. You will need to add that and the SQL statements as well, which depend on what database you are using. This topic is more in the ADO.NET realm.
By using a collection with an implementation of IList (which is an interface shared by lists and arrays). One great feature is that .NET will read the property names of your collection objects automatically. Simply create a new List or array of objects, and set the DataSource to this.
/// <summary>
/// The test class for our example.
/// </summary>
class TestObject
{
public int OneValue { get; set; }
public int TwoValue { get; set; }
}
public void Example()
{
TestObject test1 = new TestObject()
{
OneValue = 2,
TwoValue = 3
};
List<TestObject> list = new List<TestObject>();
list.Add(test1);
list.Add(test2); // Not shown in code
dataGridView1.DataSource = list;
}
Use RowHeadersVisible. Some have noticed that when you create a new DataGridView, there will be ugly row headers with arrows in the left-most column. Often, these are not desired, and you can disable them by setting RowHeadersVisible to false. This will provide the appearance in the screenshots, which is more streamlined and less distracting.
With StandardTab. This is a special property that lets you make sure that when your user tabs around on your window, the tabbing events don't get stuck in the DataGridView. Use StandardTab in the DataGridView designer to make the tab key move out of the DataGridView and to the next control. As a reminder, you need to change this in the Property pane (usually on the right).
Use the Add method. Here you want to add rows to the DataGridView programmatically. There is a collection called Rows on the DataGridView. On the rows collection, there is a method called Add. It is usually better to modify the DataSource on your data grid, but sometimes this approach is useful.
/// <summary>
/// Shows example usage of Add method on Rows.
/// </summary>
private void AddExample()
{
// n is the new index. The cells must also be accessed by an index.
// In this example, there are four cells in each row.
int n = dataGridView1.Rows.Add();
dataGridView1.Rows[n].Cells[0].Value = title;
dataGridView1.Rows[n].Cells[1].Value = dateTimeNow;
// The second cell is a date cell, use typeof DateTime class.
dataGridView1.Rows[n].Cells[1].ValueType = typeof(DateTime);
dataGridView1.Rows[n].Cells[2].Value = wordCount;
}
With CurrentCellAddress. This property returns the cell coordinates, which are also called its location or Point. You can specify X or Y or both, but in this following example, I only take the Y coordinate of the current cell. The current cell is also the selected cell, which usually has a blue highlight.
/// <summary>
/// Shows example usage of how to get the current cell.
/// </summary>
private void CurrentCellExample()
{
// Go from Y coordinate to a selected cell's value.
// DateTime is just for this example, and the Cells[1] part just
// takes the second cell for this example.
int yCoord = dataGridView1.CurrentCellAddress.Y; // You can get X if you need it.
DateTime thisDate = (DateTime)dataGridView1.Rows[yCoord].Cells[1].Value;
}
Use CellDoubleClick event and check RowIndex. In the event handler for CellDoubleClick, call the function you use for when an item is to be used. Note that you must check for e.RowIndex equals -1, which indicates that the column headers were double-clicked and not a regular cell.
void dataGridView1_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
// Do something on double click, except when the double-click is on the header.
if (e.RowIndex == -1)
{
return;
}
ProceedOpen();
}
Reminder: Click on the DataGridView in the designer, and then look at the Property pane, which is on the right bottom corner usually. Then click on the lightning bolt and scroll down to the CellDoubleClick entry. That's all you have to do to make the event here.
Listen to SelectionChanged and change controls based on the selection. In the functions called in your SelectionChanged code, check for CurrentCellAddress to figure out what was selected and where the selection moved.
void dataGridView1_SelectionChanged(object sender, EventArgs e)
{
// When our selection changes, call the function SetupButtons
// to make sure "openButton" is always in a valid state.
SetupButtons();
}
/// <summary>
/// Custom method that sets the Enabled property of a button.
/// </summary>
void SetupButtons()
{
// Disable openButton when there are no items in the data grid.
openButton.Enabled = (dataGridView1.RowCount > 0);
}
Set Columns.AutoSizeMode to Fill and the cells will expand to fill the horizontal area. Then, in the designer, set some cells to fixed or percentage width. Just allow one column to fill up the remainder--this will look great. I have to emphasize here that you need to just do a lot of manual tweaking to make things awesome.
With some custom conditional code. Windows Vista's DataGridView looks best when it has no border, but Windows XP's looks best with a border. Here's how to make column headers look awesome in both XP and Vista. What the code does is return the appropriate border attributes based on what operating system the user is running.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
dataGridView1.ColumnHeadersBorderStyle = ProperColumnHeadersBorderStyle;
}
/// <summary>
/// Remove the column header border in the Aero theme in Vista,
/// but keep it for other themes such as standard and classic.
/// </summary>
public static DataGridViewHeaderBorderStyle ProperColumnHeadersBorderStyle
{
get
{
return (SystemFonts.MessageBoxFont.Name == "Segoe UI") ?
DataGridViewHeaderBorderStyle.None :
DataGridViewHeaderBorderStyle.Raised;
}
}
}
These properties and approaches here were useful to me at some point and are in my notes, but are not really important or may not be the best way to do something. If something is really interesting or popular, I will try to expand it.
| Topic | Notes |
| dataGridView1_PreviewKeyDown | Can be used to "intercept" KeyDown events for easier processing. See my article about PreviewKeyDown. |
|
dataGridView1. Columns[0]. HeaderCell. SortGlyphDirection |
Use to draw that glyph array image. Remember to remove the glyph arrow in ColumnHeaderMouseClick. |
| BackgroundColor | Setting this to 'Window' looks best, in my opinion. It really looks professional when you adjust all the attributes to perfection. |
| SelectionMode | FullRowSelect looks the best to me and satisfied my requirements and aesthetic sense the best. |
| ColumnHeaderMouseClick |
This event is used to capture when a header is clicked. In one of my programs, I
needed to set to modify the direction that the sort glyph was pointing in the column
squares. You can check e.ColumnIndex on the event parameter to find out which of the column headers was clicked. |
| Font | DataGridView inherits the font from its containing form, and you can set the font dynamically. |
Improve the usability or appearance of the DataGridView in your program with these methods. I don't love dealing with DataGridView, but a good one can really make your program shine. Usability and appearance are two parts of the same thing, and here we consider both. DataGridView is ideal in .NET for displaying information from databases or object collections.