Page 1 of 3
WPF DataGrid (.NET 4) can be difficult to understand if you aren't used to thinking about objects and collections. This easy to follow introduction explains where the rows and columns have gone.
The big problem with most of the explanations of how the DataGrid and the examples that you will find is that they try to be realistic. They generally work with a database or some complex structured object and then explain a complicated set of steps but might be close to what you would really use the DataGrid for but they give little idea how it works. It can be difficult to separate the details that apply to the DataGrid generally and the technology it is being used with specifically.
This gives rise to questions, especially from programmers who have used other data grids, such as:
- "Where are the rows?"
- "How do I access a particular cell?"
- "How do I add another column?"
and so on.
The biggest mystery to the WPF DataGrid beginner is:
- "Where have all the rows gone?"
This article will show you exactly where they are and how the DataGrid works.
Look no binding!
Start a new Visual Studio/Express 2010 WPF project and place a DataGrid and a Button on the page.
The first problem we have to answer is where does the DataGrid get its data from? The standard answer is to use data binding and unless you understand how all this works it great detail it can obscure the simplicity of the mechanism. So while it might not be the commonest way of working let's start with a simple non-bound example.
The DataGrid will display any collection that implements IEnumerable and this means most of the collection classes that are supplied as part of the framework. When you create a DataGrid you get an empty collection object which you can access via the Items property. The Items property is read only as its purpose is to return a reference to the collection. You can however add objects to the collection using its Add method. For example:
If you try this out what you will see is a grid with some horizontal lines drawn. The lines clearly correspond to the two rows that you have just added but there is no sign of any data.
Whenever you see a grid with blank rows like this you can conclude that you have successfully given the grid some data to display but you so far have failed to set up the columns. In particular, you have failed to bind any columns to any of the data.
To see the data in the collection that we have set up we have to add some columns to the DataGrid's Columns collection. Columns do the work of actually displaying data and a DataGrid without any columns is a fairly useless object.
There are currently four types of column:
||displays text data
||displays boolean data
There is also the DataGridTemplateColumn which is completely customisable and will display any data for which there is a suitable display control.
The details of how some of these columns work is complicated - especially so the DataGridTemplateColumn - but the basic DataGridTextColumn is easy enough to use and given most simple data can be converted to text it is also very useful.
Let's add a DataGridTextColumn to the current example:
Following this addition the DataGrid now shows two rows and a single column - but still no data.
Each of the objects that make up the Items collection roughly speaking provides the data for a row of the grid. How does a column work out how to get the data it has to display from each object? The answer is that you have to setup a binding between it and the objects of the collection.
Usually each column is bound to a property of each object so that each column shows different data - but a column can be bound directly to the object. In this case the binding defaults to calling the object's ToString method to retrieve the display data. This can be useful during debugging and general development just to check that you have the correct collection associated with the grid.
In the case of our simple example it is enough to get the data displayed:
Columns).Binding = new Binding(".");
Notice that you have to cast the column to a DataGridTextColumn because the base class doesn't support a Binding property. This is one good reason for keeping a reference to any columns that you are setting up in code. That is:
DataGridTextColumn col1 =
col1.Binding = new Binding(".");
The binding "." simply means the root of the bound object, i.e. the entire object, and this means that the binding engine will call the object's ToString method. SInce the objects in the collection are Strings this displays their value as required and at last the DataGrid displays the data: