Binding to a Collection of Fields
- 5 minutes to read
When engineering a WPF application using the Model View ViewModel (MVVM) architectural pattern, you may be required to describe fields in a Model or ViewModel. The Pivot Grid can be bound to a collection of objects containing field 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. This class provides properties that correspond to settings common to all Pivot Grid fields.
- FieldTemplateSelector - describes the Pivot Grid template selector. This class allows you to choose the required template based on the specified condition.
using System.Windows;
using System.Windows.Controls;
using System.Collections.ObjectModel;
using DevExpress.Xpf.PivotGrid;
namespace Model{
public class ViewModel {
// The collection of Pivot Grid fields.
public ObservableCollection<Field> Fields { get; private set; }
// The view model that contains the field settings.
public ViewModel() {
Fields = new ObservableCollection<Field>() {
new Field() { DataFieldName="CategoryName", AreaIndex=0, FieldArea = FieldArea.RowArea, UniqueName="fieldCategory" },
new Field() { DataFieldName="Country", AreaIndex=0, FieldArea = FieldArea.ColumnArea, UniqueName="fieldCountry" },
new Field() { DataFieldName="Sales Person", AreaIndex=1, FieldArea = FieldArea.ColumnArea, UniqueName="fieldSalesPerson" },
new Field() { DataFieldName="OrderDate", AreaIndex=0, FieldArea = FieldArea.FilterArea, UniqueName="fieldOrderYear",
Interval = FieldGroupInterval.DateYear, FieldCaption = "Year", GroupName="groupYearMonth", GroupIndex=0 },
new Field() { DataFieldName="Extended Price", AreaIndex=0, FieldArea = FieldArea.DataArea, UniqueName="fieldPrice" },
};
}
}
public class Field {
public string DataFieldName { get; set; }
public string UniqueName { 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.DateYear) {
return (DataTemplate)((Control)container).FindResource("IntervalFieldTemplate");
}
return (DataTemplate)((Control)container).FindResource("DefaultFieldTemplate");
}
}
}
Note
If the Fields 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.
Field Templates and Selector
The Pivot Grid Control generates fields based on field templates. Using a template, you can create an unlimited number of fields in an unlimited number of Pivot Grid controls. In this example, there are two field templates: DefaultFieldTemplate and ComboColumnTemplate.
To avoid performance issues when binding to field properties, use the dxci:DependencyObjectExtensions.DataContext attached property. See the example below.
<!-- -->
xmlns:dxci="http://schemas.devexpress.com/winfx/2008/xaml/core/internal"
<!-- -->
<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}}"
dx:XamlHelper.Name="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).UniqueName, RelativeSource={RelativeSource Self}}"
>
</dxpg:PivotGridField>
</ContentControl>
</DataTemplate>
To choose the required template based on the specified condition, use the Template Selector. In this example, the template selector is represented by the FieldTemplateSelector class:
<Window x:Class="WpfPivotTestExample.MainWindow"
x:Name="Form1" Title="MainWindow" Height="362" Width="627"
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"
xmlns:model="clr-namespace:Model"
xmlns:view="clr-namespace:View">
<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}}"
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}}"
dx:XamlHelper.Name="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).UniqueName, RelativeSource={RelativeSource Self}}"
GroupInterval="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).Interval, RelativeSource={RelativeSource Self}}"
HeaderImage="{dx:DXImage Image=Calendar_16x16.png}">
</dxpg:PivotGridField>
</ContentControl>
</DataTemplate>
</Window.Resources>
<Grid>
<!-- -->
</Grid>
</Window>
If all Pivot Grid fields can be described using a single template, you have no need to create a field template selector. Instead, assign this template to the Pivot Grid’s PivotGridControl.FieldGeneratorTemplate property.
You can create a style to specify settings common to all fields generated using different templates. You can specify bindings to ViewModel properties within a style. This style should be assigned to the PivotGridControl.FieldGeneratorStyle property.
Customizing the WPF DXPivotGrid
Finally, specify the Pivot Grid’s PivotGridControl.DataSource, PivotGridControl.FieldsSource and PivotGridControl.FieldGeneratorTemplateSelector.
Member | Description |
---|---|
PivotGridControl.DataSource | Specifies the Pivot Grid’s data source. |
PivotGridControl.FieldsSource | Specifies the source from which the Pivot Grid generates fields. |
PivotGridControl.FieldGeneratorTemplateSelector | Specifies the field template selector, which returns a template for each field based on the specified condition. |
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}"
</dxpg:PivotGridControl>
</Grid>
The image below shows the result. As you can see, the OrderDate field has a Calendar icon in its field header.
Example
How to: Bind the Pivot Grid to Fields and Groups specified in ViewModel