For typical WPF/Silverlight business application scenarios you can quickly create and setup the DevExpress Grid in XAML:
- <dxg:GridControl ItemsSource="{Binding Source}">
- <dxg:GridControl.Columns>
- <dxg:GridColumn FieldName="FirstName"/>
- <dxg:GridColumn FieldName="LastName"/>
- </dxg:GridControl.Columns>
- <dxg:GridControl.TotalSummary>
- <dxg:GridSummaryItem FieldName="FirstName" SummaryType="Count"/>
- </dxg:GridControl.TotalSummary>
- </dxg:GridControl>
When engineering Silverlight/WPF applications using the Model-View-ViewModel (MVVM) architectural pattern, you may be required to put the code that describes columns and summaries in Model or ViewModel.
In previous versions of the DXGrid (prior to v2011 vol 1), columns could have been described via DataAnnotations attributes. In this instance, the grid automatically generated columns for all fields in a data source. The only way to customize column settings was to handle the grid’s ColumnsPopulated event in ‘code-behind’.
With the release of DXperience v2011 vol 1, DevExpress WPF/Silverlight Grid Controls support column and summary binding capabilities. The grid can be bound to ViewModel properties that represent collections of objects with column and summary settings, thus minimizing the need for ‘code-behind’ and placing column and summary definition logic in the ViewModel.
Three steps to populate columns and create summary items from the ViewModel:
- Describe columns and/or summaries in the ViewModel.
- Create columns and summary items based on ViewModel settings.
- Setup Grid Control bindings.
View Model Implementation
Let’s consider an Employee business object that contains employee information.
- public class Employee
- {
- public string FirstName { get; set; }
- public string LastName { get; set; }
- public string JobTitle { get; set; }
- public string City { get; set; }
- public DateTime BirthDate { get; set; }
- }
In a Grid Control, data fields (public properties) are represented as columns. To describe a grid column in the ViewModel, create a class whose properties correspond to column settings. Let’s create two classes:
- Column - describes a grid column used by default. This class provides properties that correspond to settings common to all grid columns types.
- ComboBoxColumn - corresponds to a grid column with a ComboBoxEdit in-place editor. This class provides the Source property that contains a list of combo box items. We’ll use this class to represent an employee’s City.
- public class Column
- {
- public string FieldName { get; set; }
- public SettingsType Settings { get; set; }
- }
-
- public class ComboColumn : Column
- {
- public IList Source { get; set; }
- }
-
- // Enumerates possible types of in-place editors used to edit cell values.
- public enum SettingsType { Default, Combo }
Next, we’ll create a collection of Column objects in the ViewModel:
- public class ViewModel {
- ...
- public List<string> Cities { get; private set; }
-
- public ObservableCollection<Column> Columns { get; private set; }
-
- public ViewModel() {
- ...
- List<string> _cities = new List<string>();
- foreach (Employee employee in Source) {
- if (!_cities.Contains(employee.City))
- _cities.Add(employee.City);
- }
- Cities = _cities;
- Columns = new ObservableCollection<Column>() {
- new Column() { FieldName = "FirstName", Settings = SettingsType.Default },
- new Column() { FieldName = "LastName", Settings = SettingsType.Default },
- new Column() { FieldName = "BirthDate", Settings = SettingsType.Default },
- new ComboColumn() { FieldName = "City", Settings = SettingsType.Combo, Source = Cities }
- };
- }
- }
To describe data summaries, we’ll create a corresponding class with summary settings:
- public class Summary
- {
- public SummaryItemType Type { get; set; }
- public string FieldName { get; set; }
- }
In the ViewModel, we’ll create GroupSumary and TotalSummary collections:
- public ObservableCollection<Summary> TotalSummary { get; private set; }
- public ObservableCollection<Summary> GroupSummary { get; private set; }
Note that we use ObservableCollection to represent the Columns, GroupSummary and TotalSummary collections. These collections should implement INotifyCollectionChanged so that changes made within the ViewModel are automatically reflected by the Grid Control.
Column Templates and Template Selector
WPF and Silverlight data templating model is a perfect solution for representing grid columns based on settings specified in the ViewModel.
Because of this flexibility, we’ll create multiple column templates - one template for each column type. By using a single template, we can create an unlimited number of columns in an unlimited number of grids.
- <Window.Resources>
- <view:ColumnTemplateSelector x:Key="ColumnTemplateSelector"/>
- <DataTemplate x:Key="DefaultColumnTemplate">
- <ContentControl>
- <dxg:GridColumn FieldName="{Binding FieldName}"/>
- </ContentControl>
- </DataTemplate>
- <DataTemplate x:Key="ComboColumnTemplate">
- <ContentControl>
- <dxg:GridColumn FieldName="{Binding FieldName}">
- <dxg:GridColumn.EditSettings>
- <dxe:ComboBoxEditSettings ItemsSource="{Binding Source}"/>
- </dxg:GridColumn.EditSettings>
- </dxg:GridColumn>
- </ContentControl>
- </DataTemplate>
- </Window.Resources>
If all grid columns can be described using a single template, assign this template to the grid’s ColumnGeneratorTemplate property; Otherwise, create a Data Template Selector.
Note: No need to worry that Silverlight does not ship with a DataTemplateSeletor. This class is included in our DevExpress.Xpf.Core library and is widely used in our cross-platform controls.
- using System.Windows;
- using System.Windows.Controls;
- using Model;
-
- namespace View {
- public class ColumnTemplateSelector : DataTemplateSelector {
- public override DataTemplate SelectTemplate(object item, DependencyObject container) {
- Column column = (Column)item;
- return (DataTemplate)((Control)container).FindResource(column.Settings + "ColumnTemplate");
- }
- }
- }
You can create a style to specify settings common to all columns generated using different templates. In WPF and Silverlight 5, you can specify bindings to ViewModel properties within a style (see FieldName below):
This style should be assigned to the grid’s ColumnGeneratorStyle property.
- <Style x:Key="ColumnStyle" TargetType="dxg:GridColumn">
- <Setter Property="FilterPopupMode" Value="CheckedList"/>
- <Setter Property="FieldName" Value="{Binding FieldName}"/>
- </Style>
Summary Template
Summary items are also generated from templates. A template that describes total summaries should be assigned to the grid’s TotalSummaryGeneratorTemplate property. A group summary template should be assigned to the GroupSummaryGeneratorTemplate property.
For purposes of this blog, it will be a single template for group and total summaries.
- <DataTemplate x:Key="SummaryTemplate">
- <ContentControl>
- <dxg:GridSummaryItem FieldName="{Binding Path=(dx:DependencyObjectExtensions.DataContext).FieldName, RelativeSource={RelativeSource Self}}"
- SummaryType="{Binding Path=(dx:DependencyObjectExtensions.DataContext).Type, RelativeSource={RelativeSource Self}}"/>
- </ContentControl>
- </DataTemplate>
Bindings Setup
For the final step, we’ll bind the grid to the Columns, TotalSummary and GroupSummary properties in the ViewModel, specify the column template selector, total and group summary templates.
- <dxg:GridControl Name="grid"
- ItemsSource="{Binding Source}"
- ColumnsSource="{Binding Columns}"
- ColumnGeneratorTemplateSelector="{StaticResource ColumnTemplateSelector}"
- TotalSummarySource="{Binding TotalSummary}"
- TotalSummaryGeneratorTemplate="{StaticResource SummaryTemplate}"
- GroupSummarySource="{Binding GroupSummary}"
- GroupSummaryGeneratorTemplate="{StaticResource SummaryTemplate}">
- <dxg:GridControl.View>
- <dxg:TableView Name="tableView1"
- AutoWidth="True"
- NavigationStyle="Cell"
- ShowTotalSummary="True"
- IsTotalSummaryMenuEnabled="False"/>
- </dxg:GridControl.View>
- </dxg:GridControl>
To see the full source code for this post, download the following example: http://www.devexpress.com/Support/Center/e/E3358.aspx.
Keep tuned to this blog for all the MVVM enhancements shipping with DevExpress Grid Controls for WPF and Silverlight.