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}" />