WPF DataGrid Control
Introduction
Since .NET 4.0, Microsoft is shipping a DataGrid control that provides all the basic functionality needed, like:
Basic usage: Auto generate columns
To show a basic data grid , just drop a DataGrid
control to your view and bind the ItemsSource
to a collection of data objects and you're done. The DataGrid provides a feature called AutoGenerateColumns
that automatically generates column according to the public properties of your data objects. It generates the following types of columns:
- TextBox columns for string values
- CheckBox columns for boolean values
- ComboBox columns for enumerable values
- Hyperlink columns for Uri values
<DataGrid ItemsSource="{Binding Customers}" />
Manually define columns
Alternatively you can define your columns manually by setting the AutoGenerateColumns
property to False
. In this case you have to define the columns in the Columns
collection of the data grid. You have the following types of columns available:
DataGridCheckBoxColumn
for boolean values
DataGridComboBoxColumn
for enumerable values
DataGridHyperlinkColumn
for Uri values
DataGridTemplateColumn
to show any types of data by defining your own cell template
DataGridTextColumn
to show text values
<DataGrid ItemsSource="{Binding Customers}" AutoGenerateColumns="False" >
<DataGrid.Columns>
<DataGridTemplateColumn Header="Image" Width="SizeToCells" IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image Source="{Binding Image}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
Selection
The data grid includes a variety of selection modes. They are configured by the SelectionMode
and SelectionUnit
property.
- The
SelectionMode
can be set to Single
or Extended
to define if one or multiple units can be selected simultaneously.
- The
SelectionUnit
defines the scope of one selection unit. It can be set to Cell
, CellAndRowHeader
and FullRow
.
<DataGrid ItemsSource="{Binding Customers}"
SelectionMode="Extended" SelectionUnit="Cell" />
Column sorting, reordering and resizing
The data grid provides features to sort, reorder and resize columns. They can be enabled or disabled by the following properties:
CanUserReorderColumns
enables or disables column re-ordering
CanUserResizeColumns
enables or disables column resizing
CanUserResizeRows
enables or disables row resizing
CanUserSortColumns
enables or disables column sorting
<DataGrid ItemsSource="{Binding Customers}"
CanUserReorderColumns="True" CanUserResizeColumns="True"
CanUserResizeRows="False" CanUserSortColumns="True"/>
Grouping
The data grid also supports grouping. To enable grouping you have to define a CollectionView
that contains to least one GroupDescription
that defines the criterias how to group.
Customers = new ListCollectionView(_customers);
Customers.GroupDescriptions.Add(new PropertyGroupDescription("Gender"));
Second thing you need to do is defining a template how the groups should look like. You can do this by setting the GroupStyle
to something like the following snippet.
<DataGrid ItemsSource="{Binding GroupedCustomers}">
<DataGrid.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=Name}" />
</StackPanel>
</DataTemplate>
</GroupStyle.HeaderTemplate>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander>
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Name}" />
<TextBlock Text="{Binding Path=ItemCount}"/>
<TextBlock Text="Items"/>
</StackPanel>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</DataGrid.GroupStyle>
</DataGrid>
Row Details
The data grid provides a feature that shows a detail panel for a selected row. It can be enabled by setting a DataTemplate to the RowDetailsTemplate
property. The data template gets the object that is bound to this row passed by the DataContext and can bind to it.
<DataGrid ItemsSource="{Binding Customers}">
<DataGrid.Columns>
<DataGridTextColumn Header="First Name" Binding="{Binding FirstName}" />
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<Image Height="100" Source="{Binding Image}" />
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
Row Details depending on the type of data
You can specify a RowDetailsTemplateSelector
that selects a data template according to the type or data that this row contains. To do this, create a type that derives from DataTemplateSelector
and override the SelectTemplate
method. In the items
argument you get the data and you can determine which data template to display. Return an instance of that data template as return value.
public class GenderTemplateSelector : DataTemplateSelector
{
public DataTemplate MaleTemplate { get; set; }
public DataTemplate FemaleTemplate { get; set; }
public override DataTemplate SelectTemplate(object item,
DependencyObject container)
{
var customer = item as Customer;
if (customer == null)
return base.SelectTemplate(item, container);
if( customer.Gender == Gender.Male)
{
return MaleTemplate;
}
return FemaleTemplate;
}
}
<l:GenderTemplateSelector x:Key="genderTemplateSelector">
<l:GenderTemplateSelector.MaleTemplate>
<DataTemplate>
<Grid Background="LightBlue">
<Image Source="{Binding Image}" Width="50" />
</Grid>
</DataTemplate>
</l:GenderTemplateSelector.MaleTemplate>
<l:GenderTemplateSelector.FemaleTemplate>
<DataTemplate>
<Grid Background="Salmon">
<Image Source="{Binding Image}" Width="50" />
</Grid>
</DataTemplate>
</l:GenderTemplateSelector.FemaleTemplate>
</l:GenderTemplateSelector>
<DataGrid ItemsSource="{Binding Customers}"
RowDetailsTemplateSelector="{StaticResource genderTemplateSelector}" />
Alternating BackgroundBrush
You can define a an AlternatingRowBackground
that is applied every even row. You can additionally specify an AlternationCount
if you only want to ink every every n-th data row.
<DataGrid ItemsSource="{Binding Customers}"
AlternatingRowBackground="Gainsboro" AlternationCount="2"/>
Frozen Columns
The data grid also supports the feature to freeze columns. That means they stay visible while you scoll horizontally through all columns. This is a useful feature to keep a referencing column like an ID or a name always visible to keep your orientation while scrolling.
To freeze a numer of columns just set the FrozenColumnCount
property to the number of columns you want to freeze.
<DataGrid ItemsSource="{Binding Customers}" FrozenColumnCount="2" />
Headers visbility
You can control the visibility of row and column headers by setting the HeadersVisibility
property to either None
,Row
,Column
or All
<DataGrid ItemsSource="{Binding Customers}" HeadersVisibility="None" />
How to template autogenerated columns
If you want to autogenerate columns using AutoGenerateColumns="True"
, you cannot use CellTemplates
, because the DataGrid
autogenerates either a text, combo, hyperlink or checkbox column, but none of these are templateable. A simple workaround is to hook into the autogeneration, cancel it and always create a DataGridTemplateColumn
. The following snippet shows the idea (the code is just a draft):
public class MyDataGrid : DataGrid
{
public DataTemplateSelector CellTemplateSelector
{
get { return (DataTemplateSelector)GetValue(CellTemplateSelectorProperty); }
set { SetValue(CellTemplateSelectorProperty, value); }
}
public static readonly DependencyProperty CellTemplateSelectorProperty =
DependencyProperty.Register("Selector", typeof(DataTemplateSelector), typeof(MyDataGrid),
new FrameworkPropertyMetadata(null));
protected override void OnAutoGeneratingColumn(DataGridAutoGeneratingColumnEventArgs e)
{
e.Cancel = true;
Columns.Add(new DataGridTemplateColumn
{
Header = e.Column.Header,
CellTemplateSelector = CellTemplateSelector
});
}
}
<l:MyDataGrid ItemsSource="{Binding}"
AutoGenerateColumns="True"
CellTemplateSelector="{StaticResource templateSelector}" />
Last modified: 2011-04-19 08:55:41
Copyright (c) by Christian Moser, 2011.
Comments on this article
|
Sreekumar |
|
|
Commented on 24.May 2011 |
Good tutorial... |
|
|
|
Shail |
|
|
Commented on 26.May 2011 |
I need to create DataGrid dynamically in special way. Let�s say I have two columns for grid 1) FieldName and 2) FieldValue which comes from database table. Now one row data could have drop down, and other row could have text, and other row could have check box in Field Value. How do I create this kind of dataGrid dynamically? My biggest challenge is interacting with ColumnTemplate in individual cell level.
FieldName | Field Value Sex | Radio Button to select Male or Female Age | Drop Down Combo box to select age from 1 to 100 Name | Text box is Employed | Check box to indicate whether employed or not
And another biggest challenge is I need to have Event on each FieldValue cell. Event could be click, double click, Right mouse click, Enter etc. Thank you Shail |
|
|
|
Anil Kumar... |
|
|
Commented on 30.May 2011 |
Very very nice article explaining every aspect of the grid with a Good Code example. Eager to see some more articles on various controls.. |
|
|
|
patel... |
|
|
Commented on 10.June 2011 |
please help i bind complete datagrid but how 2 work same as datagridview in window appllication like dg.Rows.column.cell is not in datagrid and how 2 count totalrows like dg.rows.counthow 2 do in datagrid |
|
|
|
patel... |
|
|
Commented on 10.June 2011 |
which control equel datagridview in window app to wpf vs2010 reason i new in wpf vs 2010 |
|
|
|
bhagavan |
|
|
Commented on 17.June 2011 |
awesome..i think its a knowledge of ocean |
|
|
|
eshao |
|
|
Commented on 5.July 2011 |
The datagrid in net4.0 is not good supported for mvvm. THe datagrid don't have the "command" property like button, |
|
|
|
eshao |
|
|
Commented on 5.July 2011 |
if u use the datagrid wirh mvvm, u must do lot extra work that will hit u out off earth. |
|
|
|
Srinivas |
|
|
Commented on 7.July 2011 |
Superb, very Nice Article. It helped me a Lot. Thank U. |
|
|
|
Dan |
|
|
Commented on 13.July 2011 |
There is a great problem using grouping - when you call .Refresh() method of ListCollectionView, to update layout, it redraws all the datagrid and close all your groups. May anybody answer how to refresh the data without those problems? |
|
|
|
Dan |
|
|
Commented on 13.July 2011 |
There is a great problem using grouping - when you call .Refresh() method of ListCollectionView, to update layout, it redraws all the datagrid and close all your groups. May anybody answer how to refresh the data without those problems? |
|
|
|
Dev |
|
|
Commented on 21.July 2011 |
How did you made the View Source option disable on this page? |
|
|
|
Luis |
|
|
Commented on 23.July 2011 |
What should I do if I want another node directioned from the costumers class? e.g. public class Customer : INotifyPropertyChanged { private string _firstName; private string _lastName; private Gender _gender; private Uri _webSite; private bool _newsletter; private string _image; private Phone _phones;// <-------- this one . . . } //where:
public class Phone:INotifyPropertyChanged { private int _homeNumber; private int _celNumber; private int _workNumber; private int _faxNumber; . . . }
I want to display "Phone" values on a dataGrid, preferibly in a comboboxCell, I just want to display them, not edit them
thanks |
|
|
|
Luis |
|
|
Commented on 23.July 2011 |
What should I do if I want another node directioned from the costumers class? e.g. public class Customer : INotifyPropertyChanged { private string _firstName; private string _lastName; private Gender _gender; private Uri _webSite; private bool _newsletter; private string _image; private Phone _phones;// <-------- this one . . . } //where:
public class Phone:INotifyPropertyChanged { private int _homeNumber; private int _celNumber; private int _workNumber; private int _faxNumber; . . . }
I want to display "Phone" values on a dataGrid, preferibly in a comboboxCell, I just want to display them, not edit them
thanks |
|
|
|
Derek |
|
|
Commented on 27.July 2011 |
Is there anyway to get those check boxes to work with one click? The currently require two clicks to use. One to select the cell and one to click the check box. |
|
|
|
Prabhat khare |
|
|
Commented on 28.July 2011 |
I have a problem on paging,in which i want to show google type paging like 1 2 3 4...400 please suggest me, |
|
|
|
Steve |
|
|
Commented on 2.August 2011 |
Hari Kumar (and others) you are missing the point of the WPF datagrid, you don't access the rows/cells directly, the datagrid should be bound to a data set, changes made on the screen are reflected back to the data set and if you change the data set these changes are reflected on the screen.
It takes a bit of getting used to, but it's very powerfull once you understand how to use it. |
|
|
|
Chirag |
|
|
Commented on 10.August 2011 |
Would anyone know, how to make the grids look a bit more stylish as opposed to the normal windows 'blue' selection. I would like to add a bit more touch and feel |
|
|
|
zahra |
|
|
Commented on 20.August 2011 |
tanks alot.very good |
|
|
|
Ruslan |
|
|
Commented on 23.August 2011 |
I have a question about grouping. Let's say, I have a group style in resource dictionary, and I want to set datagrid group style to the group style from xaml. How can this be achieved? Thank you in advance, Ruslan |
|
|
|
Ruslan |
|
|
Commented on 23.August 2011 |
I have a question about grouping. Let's say, I have a group style in resource dictionary, and I want to set datagrid group style to the group style from xaml. How can this be achieved? Thank you in advance, Ruslan |
|
|
|
Soby Mathew |
|
|
Commented on 31.August 2011 |
very Nice Article. |
|
|
|
Bhavneet |
|
|
Commented on 12.September 2011 |
can u help me out? actually problem is that i'm doing a project in WPF but when i drag grid on it then there is no property for autocolomn property or add colomn property.is the problem is of studio problem? i'm using visual studio 2008.. |
|
|
|
detective jeera |
|
|
Commented on 23.September 2011 |
Nice Article. Thanks for such a nice article. |
|
|
|
Harikrishnan |
|
|
Commented on 27.September 2011 |
Superb article. How can I generate column dynamically from user preference column number values? Ex: If I have 3 columns C1,C2,C3 and user chenges the order to C3,C1,C2 - I have to load the same way the user changed it the next time... Can anyone Help!!!! |
|