Binding to a Collection of Bands

  • 5 minutes to read

When engineering a WPF application using the MVVM architectural pattern, you may be required to describe bands in a Model or ViewModel. The GridControl can automatically retrieve settings for bands from a Model or ViewModel.

View Model Implementation

Assume an Employee view model. It includes the following classes.

  • Employee - a data object that contains employee information (e.g., first and last names, job title, etc.).
  • ViewModel - the employee view model.
  • EmployeeData - a collection of the Employee objects, displayed within grid.
  • Column - describes a grid column. This class provides properties that correspond to grid column settings.
  • Band - describes a grid band. This class provides the ChildColumns property, which contains the list of child columns for each band.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace GridMvvmEnhancements {
    public class ViewModel {
        // Returns a list of employees so that they can be bound to the grid control. 
        public List<Employee> Source { get; private set; }
        // The collection of grid columns. 
        public ObservableCollection<Band> Bands { get; private set; }
        public ViewModel() {
            Source = EmployeeData.DataSource;
            Bands = new ObservableCollection<Band>() {
                new Band() {
                    Header = "Personal Info",
                    ChildColumns = new ObservableCollection<Column>() {
                        new Column() { FieldName = "FirstName" },
                        new Column() { FieldName = "LastName" },
                        new Column() { FieldName = "BirthDate" }
                    }
                },
                new Band() {
                    Header = "Location",
                    ChildColumns = new ObservableCollection<Column>() {
                        new Column() { FieldName = "City" },
                        new Column() { FieldName = "Address" }
                    }
                },
                new Band() {
                    Header = "Position",
                    ChildColumns = new ObservableCollection<Column>() {
                        new Column() { FieldName = "JobTitle" },
                    }
                }
            };
        }
    }
    // The data item. 
    public class Employee {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string City { get; set; }
        public string Address { get; set; }
        public string JobTitle { get; set; }
        public DateTime BirthDate { get; set; }
    }
    public class EmployeeData : List<Employee> {
        public static List<Employee> DataSource {
            get {
                List<Employee> list = new List<Employee>();
                list.Add(new Employee() {
                    FirstName = "Nathan", LastName = "White", City = "NY", Address = "90 7th Street",
                    JobTitle = "Sales Manager", BirthDate = new DateTime(1970, 1, 10)
                });
                list.Add(new Employee() {
                    FirstName = "Sandra", LastName = "Oldman", City = "LA", Address = "3687 Mohawk Street",
                    JobTitle = "Marketing Manager", BirthDate = new DateTime(1970, 7, 22)
                });
                return list;
            }
        }
    }
    public class Column {
        // Specifies the name of a data source field to which the column is bound. 
        public string FieldName { get; set; }
    }
    // Corresponds to a band column. 
    public class Band {
        // Specifies the band header.
        public string Header { get; set; }
        public ObservableCollection<Column> ChildColumns { get; set; }
    }
}
NOTE

If the Bands collection might be changed after it has been assigned to the grid control, it should implement INotifyCollectionChanged, so that changes made within a View Model are automatically reflected by the grid.

Band Templates and Template Selector

The GridControl generates bands and their child columns based on band and column templates.

TIP

To learn about column templates, refer to the Binding to a Collection of Columns topic.

To avoid performance issues when binding to band (and column) properties, use the dxci:DependencyObjectExtensions.DataContext attached property.

To choose the required template based on the band settings, use the template selector.

The code sample below demonstrates how to implement templates for grid bands (see XAML: SingleColumnBandTemplate and MultiColumnBandTemplate) and columns and how to implement the band template selector (the BandTemplateSelector class).

<Window x:Class="GridMvvmEnhancements.MainWindow" 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        Title="MainWindow" Height="350" Width="525" 
        xmlns:dxg="http://schemas.devexpress.com/winfx/2008/xaml/grid" 
        xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors" 
        xmlns:dxci="http://schemas.devexpress.com/winfx/2008/xaml/core/internal" 
        xmlns:local="clr-namespace:GridMvvmEnhancements">
    <Window.DataContext>
        <local:ViewModel/>
    </Window.DataContext>
    <Window.Resources>
        <local:BandTemplateSelector x:Key="BandTemplateSelector"/>
        <DataTemplate x:Key="ColumnTemplate">
            <ContentControl>
                <dxg:GridColumn FieldName="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).FieldName, RelativeSource={RelativeSource Self}}" />
            </ContentControl>
        </DataTemplate>
        <DataTemplate x:Key="MultiColumnBandTemplate">
            <ContentControl>
                <dxg:GridControlBand Header="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).Header, RelativeSource={RelativeSource Self}}"
                                     ColumnsSource="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).ChildColumns, RelativeSource={RelativeSource Self} }"
                                     ColumnGeneratorTemplate="{StaticResource ColumnTemplate}">
                </dxg:GridControlBand>
            </ContentControl>
        </DataTemplate>
        <DataTemplate x:Key="SingleColumnBandTemplate">
            <ContentControl>
                <!-- For bands with a single child column. Setting the OverlayHeaderByChildren property to "True" makes a child column to overlay its parent band's header -->
                <dxg:GridControlBand Header="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).Header, RelativeSource={RelativeSource Self}}"
                                     ColumnsSource="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).ChildColumns, RelativeSource={RelativeSource Self} }"
                                     ColumnGeneratorTemplate="{StaticResource ColumnTemplate}" 
                                     OverlayHeaderByChildren="True" />
            </ContentControl>
        </DataTemplate>
    </Window.Resources>
    <Grid>
    </Grid>
</Window>
using System.Windows;
using System.Windows.Controls;

namespace GridMvvmEnhancements {
...
    public class BandTemplateSelector : DataTemplateSelector {
        public override DataTemplate SelectTemplate(object item, DependencyObject container) {
            Band band = (Band)item;
            if(band.ChildColumns.Count == 1) {
                return (DataTemplate)((Control)container).FindResource("SingleColumnBandTemplate");
            }
            return (DataTemplate)((Control)container).FindResource("MultiColumnBandTemplate");
        }
    }
}
NOTE

If all grid bands can be described using a single template, you have no need to create a band template selector. Instead, assign this template to the grid's DataControlBase.BandGeneratorTemplate property.

Binding GridControl to ViewModel

To bind the GridControl to a ViewModel, specify the following properties.

<Grid>
        <dxg:GridControl Name="grid" 
                         ItemsSource="{Binding Source}" 
                         BandsSource="{Binding Bands}"
                         BandGeneratorTemplateSelector="{StaticResource BandTemplateSelector}">
            <dxg:GridControl.View>
                <dxg:TableView AutoWidth="True"/>
            </dxg:GridControl.View>
        </dxg:GridControl>
    </Grid>

The image below illustrates the result.

WPF_Grid_MVVM_BandColumns

See Also