Back to Devexpress

How to: Bind the Grid to a Collection of Columns

wpf-10121-controls-and-libraries-data-grid-mvvm-enhancements-examples-binding-to-a-collection-of-columns.md

latest10.9 KB
Original Source

How to: Bind the Grid to a Collection of Columns

  • Oct 06, 2025
  • 7 minutes to read

This topic defines columns in a View Model and display them in the GridControl.

View Example: How to Bind the GridControl to a Collection of Columns Specified in a ViewModel

Assign ViewModel Columns to the GridControl

This scenario displays information from an employee data model in the GridControl.

  1. Create a class that describes a grid column:

  2. Specify a collection of columns in the ViewModel:

  3. The GridControl generates columns based on column templates. Add a default column template.

  4. Assign the column collection to the DataControlBase.ColumnsSource property. Set the DataControlBase.ColumnGeneratorTemplate property to a template that generates columns:

Add a Lookup Column

If you want to specify extra column types (for example, to display a list of states in a column’s combo box), follow the steps below:

  1. Add an enumeration that lists column types:

  2. Create a class that describes a lookup column:

  3. Add a lookup column to the ViewModel’s Columns collection and specify the lookup’s data source:

  4. Create a template that generates lookup columns:

Add a Template Selector to Choose among Multiple Templates

Your application now contains the DefaultColumnTemplate and LookupColumnTemplate. To choose a template based on the column type, create a template selector and assign it to the DataControlBase.ColumnGeneratorTemplateSelector property:

csharp
using System.Windows;
using System.Windows.Controls;

namespace ColumnsSample {
    public class ColumnTemplateSelector : DataTemplateSelector {
        public DataTemplate DefaultColumnTemplate { get; set; }
        public DataTemplate LookupColumnTemplate { get; set; }

        public override DataTemplate SelectTemplate(object item, DependencyObject container) {
            Column column = item as Column;
            if(column == null) return null;
            switch(column.Settings) {
                case SettingsType.Default:
                    return DefaultColumnTemplate;
                case SettingsType.Lookup:
                    return LookupColumnTemplate;
            }
            return null;
        }
    }
}
vb
Imports System.Windows
Imports System.Windows.Controls

Namespace ColumnsSample
    Public Class ColumnTemplateSelector
        Inherits DataTemplateSelector

        Public Property DefaultColumnTemplate() As DataTemplate
        Public Property LookupColumnTemplate() As DataTemplate

        Public Overrides Function SelectTemplate(ByVal item As Object, ByVal container As DependencyObject) As DataTemplate
            Dim column As Column = TryCast(item, Column)
            If column Is Nothing Then
                Return Nothing
            End If
            Select Case column.Settings
                Case SettingsType.Default
                    Return DefaultColumnTemplate
                Case SettingsType.Lookup
                    Return LookupColumnTemplate
            End Select
            Return Nothing
        End Function
    End Class
End Namespace
xaml
<Window ...
    xmlns:dxg="http://schemas.devexpress.com/winfx/2008/xaml/grid">
    <Window.Resources>
        <!-- ... -->
        <local:ColumnTemplateSelector x:Key="ColumnTemplateSelector"
                                      DefaultColumnTemplate ="{StaticResource DefaultColumnTemplate}"
                                      LookupColumnTemplate ="{StaticResource LookupColumnTemplate}"/>
    </Window.Resources>
    <dxg:GridControl ItemsSource="{Binding Source}" 
                     ColumnsSource="{Binding Columns}"
                     ColumnGeneratorTemplateSelector="{StaticResource ColumnTemplateSelector}"/>
</Window>

Specify Column Settings

You can use the DataControlBase.ColumnGeneratorStyle property to create a style that specifies column settings. The GridControl applies these settings to all columns generated from templates:

xaml
<Window ...
    xmlns:dxg="http://schemas.devexpress.com/winfx/2008/xaml/grid">
    <dxg:GridControl.ColumnGeneratorStyle>
        <Style TargetType="dxg:GridColumn">
            <Setter Property="FilterPopupMode" Value="CheckedList" />
            <Setter Property="Width" Value="Auto" />
            <Setter Property="ReadOnly" Value="True" />
            <Setter Property="HorizontalHeaderContentAlignment" Value="Center" />
            <Setter Property="HeaderStyle">
                <Setter.Value>
                    <Style TargetType="dxg:BaseGridHeader">
                        <Setter Property="FontWeight" Value="SemiBold" />
                    </Style>
                </Setter.Value>
            </Setter>
        </Style>
    </dxg:GridControl.ColumnGeneratorStyle>
</Window>

You can also use multiple data annotation attributes to define validation rules and format options:

csharp
public class Employee {
    [ReadOnly(true)]
    public string FirstName { get; set; }
    [MinLength(3)]
    public string LastName { get; set; }
    public string StateProvinceName { get; set; }
}
vb
Public Class Employee
    <[ReadOnly](True)>
    Public Property FirstName As String
    <MinLength(3)>
    Public Property LastName As String
    Public Property StateProvinceName As String
End Class

Add Columns That Use the Binding Property

In some cases, you should use the ColumnBase.Binding property instead of the ColumnBase.FieldName property to associate columns with data source fields (for example, to implement custom converters or access collection members). The ColumnBase.Binding property is not a dependency property and cannot be bound. Use the following binding helper to assign a binding to the ColumnBase.Binding property:

csharp
using DevExpress.Xpf.Grid;
using System.Windows;
using System.Windows.Data;

namespace ColumnsSample {
    public static class BindingHelper {
        public static string GetPath(GridColumn obj) {
            return (string)obj.GetValue(PathProperty);
        }
        public static void SetPath(GridColumn obj, string value) {
            obj.SetValue(PathProperty, value);
        }
        public static readonly DependencyProperty PathProperty = DependencyProperty.RegisterAttached("Path", typeof(string), typeof(BindingHelper),
            new PropertyMetadata((d, e) => { 
                if (!string.IsNullOrWhiteSpace(e.NewValue as string)) 
                    ((GridColumn)d).Binding = new Binding((string)e.NewValue) { 
                        Mode = BindingMode.TwoWay 
                    }; 
            })
        );
    }
}
vb
Imports DevExpress.Xpf.Grid
Imports System.Windows
Imports System.Windows.Data

Namespace ColumnsSample

    Public Module BindingHelper

        Public Function GetPath(ByVal obj As GridColumn) As String
            Return CStr(obj.GetValue(PathProperty))
        End Function

        Public Sub SetPath(ByVal obj As GridColumn, ByVal value As String)
            obj.SetValue(PathProperty, value)
        End Sub

        Public ReadOnly PathProperty As DependencyProperty = DependencyProperty.RegisterAttached("Path", GetType(String), GetType(BindingHelper), New PropertyMetadata(Sub(d, e)
            If Not String.IsNullOrWhiteSpace(TryCast(e.NewValue, String))
                Then CType(d, GridColumn).Binding = New Binding(CStr(e.NewValue)) With {
                    .Mode = BindingMode.TwoWay
                }
        End Sub))
    End Module
End Namespace
xaml
<Window ...
        xmlns:dxg="http://schemas.devexpress.com/winfx/2008/xaml/grid" 
        xmlns:dxci="http://schemas.devexpress.com/winfx/2008/xaml/core/internal">
    <DataTemplate x:Key="BindingColumnTemplate">
        <dxg:GridColumn local:BindingHelper.Path="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).FieldName, RelativeSource={RelativeSource Self}}"
                        Header="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).Header, RelativeSource={RelativeSource Self}}"/>
    </DataTemplate>
</Window>
csharp
public class ViewModel : ViewModelBase {
    public ViewModel() {
        Columns = new ObservableCollection<Column>() {
            // ...
            new BindingColumn( SettingsType.Binding, "Cities[0]", "City1" ),
            new BindingColumn( SettingsType.Binding, "Cities[1]", "City2" )
        };
    }
    public ObservableCollection<Column> Columns { get; }
}

public class BindingColumn : Column {
    public BindingColumn(SettingsType settings, string fieldname, string header): base(settings, fieldname) {
        Header = header;
    }
    public string Header { get; }
}
vb
Public Class ViewModel
    Inherits ViewModelBase

    Public Sub New()
        Columns = New ObservableCollection(Of Column)() From {
            ' ...
            New BindingColumn(SettingsType.Binding, "Cities[0]", "City1"), 
            New BindingColumn(SettingsType.Binding, "Cities[1]", "City2")}
    End Sub

    Public ReadOnly Property Columns As ObservableCollection(Of Column)
End Class

Public Class BindingColumn
    Inherits Column

    Public Sub New(ByVal settings As SettingsType, ByVal fieldname As String, ByVal header As String)
        MyBase.New(settings, fieldname)
        Me.Header = header
    End Sub

    Public ReadOnly Property Header As String
End Class

See Also

Bind to Collections Specified in the ViewModel