Binding to a Collection of Groups
- 5 minutes to read
When engineering a WPF application using the Model View ViewModel (MVVM) architectural pattern, you may be required to describe field groups in a Model or ViewModel. The Pivot Grid can be bound to a collection of objects containing group settings, described in a Model or ViewModel, thus minimizing the need for ‘code-behind’.
View Model Implementation
Note
In this tutorial PivotGrid is bound to the Sales Person view of the Northwind database. You can find it at C:\Users\Public\Documents\DevExpress Demos 24.1\Components\Data\nwind.mdb.
Create a view model. In this tutorial, the view model includes the following classes:
- ViewModel - the Sales Person view model.
- Field - describes the Pivot Grid fields. To get more information about field templates, see Binding to a Collection of Fields.
- FieldTemplateSelector - describes the Pivot Grid template selector. This class allows you to choose the required template based on the specified condition.
- Group - describes the Pivot Grid groups. This class provides properties that correspond to settings common to all Pivot Grid field groups.
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using DevExpress.Xpf.PivotGrid;
namespace PivotGridMvvmEnhancements {
public class ViewModel {
// The collection of Pivot Grid fields.
public ObservableCollection<Field> Fields { get; private set; }
// The collection of Pivot Grid groups.
public ObservableCollection<FieldGroup> Groups { get; private set; }
// The view model that contains the fields and groups settings.
public ViewModel() {
Fields = new ObservableCollection<Field>() {
new Field() { FieldName="Country", AreaIndex=0, FieldArea = FieldArea.RowArea, Name="fieldCountry",
GroupName="groupSalesPerson", GroupIndex=0},
new Field() { FieldName="Sales Person", AreaIndex=1, FieldArea = FieldArea.RowArea, Name="fieldSalesPerson",
GroupName="groupSalesPerson", GroupIndex=1},
new Field() { FieldName="OrderDate", AreaIndex=0, FieldArea = FieldArea.ColumnArea, Name="fieldOrderYear",
Interval = FieldGroupInterval.DateYear, FieldCaption = "Year", GroupName="groupYearMonth", GroupIndex=0 },
new Field() { FieldName="OrderDate", AreaIndex=1, FieldArea = FieldArea.ColumnArea, Name="fieldOrderMonth",
Interval = FieldGroupInterval.DateMonth, FieldCaption = "Month", GroupName="groupYearMonth", GroupIndex=1 },
new Field() { FieldName="Extended Price", AreaIndex=0, FieldArea = FieldArea.DataArea, Name="fieldPrice" },
};
Groups = new ObservableCollection<FieldGroup>() {
new FieldGroup() { GroupName = "groupYearMonth" },
new FieldGroup() { GroupName = "groupSalesPerson" }
};
}
}
public class Field {
public string FieldName { get; set; }
public string Name { get; set; }
public string FieldCaption { get; set; }
public FieldArea FieldArea { get; set; }
public int AreaIndex { get; set; }
public FieldGroupInterval Interval { get; set; }
public string GroupName { get; set; }
public int GroupIndex { get; set; }
}
public class FieldTemplateSelector : DataTemplateSelector {
public override DataTemplate SelectTemplate(object item, DependencyObject container) {
Field field = (Field)item;
if(field.Interval == FieldGroupInterval.DateMonth || field.Interval == FieldGroupInterval.DateYear) {
return (DataTemplate)((Control)container).FindResource("IntervalFieldTemplate");
}
return (DataTemplate)((Control)container).FindResource("DefaultFieldTemplate");
}
}
public class FieldGroup {
public string GroupName { get; set; }
}
}
Note
If the Groups collection might be changed after it has been assigned to the Pivot Grid control, it should implement the INotifyCollectionChanged interface, so that changes made within a View Model are automatically reflected by the Pivot Grid.
Group Templates and Selector
The Pivot Grid Control generates groups based on group templates. Using a template, you can create an unlimited number of field groups in an unlimited number of Pivot Grid controls. In this example, there is one group template: DefaultGroupTemplate.
To avoid performance issues when binding to field properties, use the dxci:DependencyObjectExtensions.DataContext attached property.
If all Pivot Grid groups can be described using a single template, you have no need to create a field template selector:
<Window x:Class="WpfPivotTestExample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfPivotTestExample"
xmlns:dxpg="http://schemas.devexpress.com/winfx/2008/xaml/pivotgrid"
xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
xmlns:dxci="http://schemas.devexpress.com/winfx/2008/xaml/core/internal"
xmlns:nwindDataSetTableAdapters="clr-namespace:WpfPivotTestExample.nwindDataSetTableAdapters"
x:Name="Form1"
Title="MainWindow" Height="362" Width="627">
<Window.DataContext>
<local:ViewModel />
</Window.DataContext>
<Window.Resources>
<local:FieldTemplateSelector x:Key="FieldTemplateSelector" />
<dx:TypedSimpleSource x:Key="TypedSimpleSource" AdapterType="{x:Type nwindDataSetTableAdapters:SalesPersonTableAdapter}"
ContextType="{x:Type local:nwindDataSet}" Path="SalesPerson" />
<DataTemplate x:Key="DefaultFieldTemplate">
<ContentControl>
<dxpg:PivotGridField FieldName="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).FieldName, RelativeSource={RelativeSource Self}}"
Area="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).FieldArea, RelativeSource={RelativeSource Self}}"
AreaIndex="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).AreaIndex, RelativeSource={RelativeSource Self}}"
Caption="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).FieldCaption, RelativeSource={RelativeSource Self}}"
GroupName="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).GroupName, RelativeSource={RelativeSource Self}}"
GroupIndex="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).GroupIndex, RelativeSource={RelativeSource Self}}"
dx:XamlHelper.Name="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).UniqueName, RelativeSource={RelativeSource Self}}"
>
</dxpg:PivotGridField>
</ContentControl>
</DataTemplate>
<DataTemplate x:Key="IntervalFieldTemplate">
<ContentControl>
<dxpg:PivotGridField FieldName="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).FieldName, RelativeSource={RelativeSource Self}}"
Area="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).FieldArea, RelativeSource={RelativeSource Self}}"
AreaIndex="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).AreaIndex, RelativeSource={RelativeSource Self}}"
Caption="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).FieldCaption, RelativeSource={RelativeSource Self}}"
GroupName="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).GroupName, RelativeSource={RelativeSource Self}}"
GroupIndex="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).GroupIndex, RelativeSource={RelativeSource Self}}"
GroupInterval="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).Interval, RelativeSource={RelativeSource Self}}"
dx:XamlHelper.Name="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).UniqueName, RelativeSource={RelativeSource Self}}"
HeaderImage="{dx:DXImage Image=Calendar_16x16.png}">
</dxpg:PivotGridField>
</ContentControl>
</DataTemplate>
<DataTemplate x:Key="GroupTemplate">
<ContentControl>
<dxpg:PivotGridGroup
dx:XamlHelper.Name="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).GroupName, RelativeSource={RelativeSource Self}}">
</dxpg:PivotGridGroup>
</ContentControl>
</DataTemplate>
</Window.Resources>
<Grid>
<!-- -->
</Grid>
</Window>
To create more then one template for field groups to allow choosing the required template based on a specified condition, create the Template Selector. After that, assign this class containing the specified condition to the Pivot Grid’s PivotGridControl.GroupGeneratorTemplateSelector property.
You can create a style to specify settings common to all field groups generated using different templates. You can specify bindings to ViewModel properties within a style. This style should be assigned to the PivotGridControl.GroupGeneratorStyle property.
Customizing the WPF DXPivotGrid
Finally, specify the Pivot Grid’s PivotGridControl.DataSource, PivotGridControl.GroupsSource and PivotGridControl.GroupGeneratorTemplate.
Member | Description |
---|---|
PivotGridControl.DataSource | Specifies the Pivot Grid’s data source. |
PivotGridControl.GroupsSource | Specifies the source from which the Pivot Grid generates groups. |
PivotGridControl.GroupGeneratorTemplate | Specifies the group template. |
The following code shows how to configure the Pivot Grid control using the ViewModel.
<Grid>
<dxpg:PivotGridControl x:Name="pivotGridControl1"
DataSource="{Binding Data, Source={StaticResource TypedSimpleSource}}"
FieldsSource="{Binding Fields }"
FieldGeneratorTemplateSelector="{StaticResource FieldTemplateSelector}"
GroupsSource="{Binding Groups}"
GroupGeneratorTemplate="{StaticResource GroupTemplate}">
</dxpg:PivotGridControl>
</Grid>
The image below illustrates the result.
Example
How to: Bind the Pivot Grid to Fields and Groups specified in ViewModel