How to: Bind the Grid to a Collection of Conditional Formatting Rules

  • 6 minutes to read

This topic describes how to define conditional formatting rules in a View Model and apply them to the GridControl.

View Example: How to Bind the GridControl to Conditional Formatting Rules Specified in a ViewModel

Apply Conditional Formatting Rules specified in a ViewModel to the GridControl

This example creates a conditional formatting rule that highlights rows.

DevExpress WPF | Grid Control - MVVM Conditional Formatting

Specify Format Conditions in the ViewModel

  1. Create an enumeration that lists comparison rules you want to use in conditional formatting rules:

    public enum ConditionRule { Less, Greater }
    
  2. Create a class that describes a conditional formatting rule:

    public class FormattingRule : BindableBase {
        public FormattingRule(string fieldname, ConditionRule valuerule, int value, bool applytorow) {
            FieldName = fieldname;
            ValueRule = valuerule;
            Value = value;
            ApplyToRow = applytorow;
        }
        public string FieldName { get; }
        public ConditionRule ValueRule { get; }
        public int Value { get; }
        public bool ApplyToRow { get; }
    }
    
  3. Specify a collection of conditional formatting rules in the ViewModel:

    public class ViewModel : ViewModelBase {
        public ViewModel() {
            // ...
            Rules = new ObservableCollection<FormattingRule>() {
                new FormattingRule("Total", ConditionRule.Less, 0, true)
            };
        }
        // ...
        public ObservableCollection<FormattingRule> Rules { get; }
    }
    

    If you want the GridControl to reflect changes made in the Rules collection, this collection should implement the INotifyCollectionChanged interface.

Create a Format Condition Template

  1. To specify a rule’s comparison operator, set the FormatCondition.ValueRule property to a ConditionRule enumeration value. Create an ObjectToObjectConverter to map your ConditionRule enumeration values to the ConditionRule enumeration values:

    <Window ...
        xmlns:dxmvvm="http://schemas.devexpress.com/winfx/2008/xaml/mvvm">
        <Window.Resources>
            <dxmvvm:ObjectToObjectConverter x:Key="FormatRuleConverter">
                <dxmvvm:MapItem Source="Less" Target="Less"/>
                <dxmvvm:MapItem Source="Greater" Target="Greater"/>
            </dxmvvm:ObjectToObjectConverter>
        </Window.Resources>
    
  2. Create a template that generates conditional formatting rules.

    Use the FormatRuleConverter to specify the Converter parameter for the FormatCondition.ValueRule property.

    Use the DependencyObjectExtensions.DataContext attached property when you bind the GridControl to conditional formatting properties. This attached property synchronizes data updates of bound properties to enhance grid performance:

    <Window.Resources>
        <DataTemplate x:Key="BackgroundTemplate">
            <ContentControl>
                <dxg:FormatCondition 
                    FieldName="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).FieldName, RelativeSource={RelativeSource Self}}"
                    ValueRule="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).Rule, RelativeSource={RelativeSource Self}, Converter={StaticResource FormatRuleConverter}}"
                    Value1="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).Value, RelativeSource={RelativeSource Self}}"
                    ApplyToRow="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).ApplyToRow, RelativeSource={RelativeSource Self}}"
                    PredefinedFormatName="LightRedFill"/>
            </ContentControl>
        </DataTemplate>
    </Window.Resources>
    

Apply Format Conditions to the GridControl

  1. Assign the conditional formatting rule collection to the TableView.FormatConditionsSource property.
  2. Set the TableView.FormatConditionGeneratorTemplate property to a template that generates conditional formatting rules.
<dxg:GridControl ItemsSource="{Binding Orders}">
    <!-- ... -->
    <dxg:GridControl.View>
        <dxg:TableView FormatConditionsSource="{Binding Rules}"
                       FormatConditionGeneratorTemplate="{StaticResource BackgroundFormat}"/>
    </dxg:GridControl.View>
</dxg:GridControl>

Add Multiple Conditional Formatting Rules

If you want to specify extra format conditions, follow the steps below. This example demonstrates how to add format conditions that change a cell’s font and display an image in this cell.

DevExpress WPF | Grid Control - MVVM Multiple Format Conditions

  1. Specify an enumeration that lists format condition types:

    public enum FormattingType { Background, Font, Icon }
    
  2. Add a property that returns a format condition type to the Rule class:

    public class FormattingRule : BindableBase {
        public FormattingRule(string fieldname, ConditionRule valuerule, int value, bool applytorow, FormattingType type) {
            FieldName = fieldname;
            ValueRule = valuerule;
            Value = value;
            ApplyToRow = applytorow;
            Type = type;
        }
        public string FieldName { get; }
        public ConditionRule ValueRule { get; }
        public int Value { get; }
        public bool ApplyToRow { get; }
        public FormattingType Type { get; }
    }
    
  3. Add conditional formatting rules to the Rules collection:

    public class ViewModel : ViewModelBase {
        public ViewModel() {
            // ...
            Rules = new ObservableCollection<FormattingRule>() {
                new FormattingRule("Total", ConditionRule.Less, 0, true, FormattingType.Background),
                new FormattingRule( nameof(Order.Discount), ConditionRule.Greater, 0, false, FormattingType.Font),
                new FormattingRule( nameof(Order.Discount), ConditionRule.Greater, 0, false, FormattingType.Icon)
            };
        }
        // ...
        public ObservableCollection<FormattingRule> Rules { get; }
    }
    
  4. Create templates that generate conditional formatting rules:

    <Window ...
        xmlns:dxci="http://schemas.devexpress.com/winfx/2008/xaml/core/internal"
        xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core">
        <Window.Resources>
            <!-- ... -->
            <DataTemplate x:Key="FontTemplate">
                <ContentControl>
                    <dxg:FormatCondition 
                        FieldName="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).FieldName, RelativeSource={RelativeSource Self}}"
                        ValueRule="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).ValueRule, RelativeSource={RelativeSource Self}, Converter={StaticResource FormatRuleConverter}}"
                        Value1="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).Value, RelativeSource={RelativeSource Self}}"
                        ApplyToRow="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).ApplyToRow, RelativeSource={RelativeSource Self}}"
                        PredefinedFormatName="BoldText"/>
                </ContentControl>
            </DataTemplate>
    
            <DataTemplate x:Key="IconTemplate">
                <ContentControl>
                    <dxg:FormatCondition 
                        FieldName="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).FieldName, RelativeSource={RelativeSource Self}}"
                        ValueRule="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).ValueRule, RelativeSource={RelativeSource Self}, Converter={StaticResource FormatRuleConverter}}"
                        Value1="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).Value, RelativeSource={RelativeSource Self}}"
                        ApplyToRow="{Binding Path=(dxci:DependencyObjectExtensions.DataContext).ApplyToRow, RelativeSource={RelativeSource Self}}">
                        <dxg:FormatCondition.Format>
                            <dx:Format Icon="{dx:IconSet Name=Stars3_1}"/>
                        </dxg:FormatCondition.Format>
                    </dxg:FormatCondition>
                </ContentControl>
            </DataTemplate>
        </Window.Resources>
    

Add a Template Selector to Choose among Multiple Templates

Your application now contains the BackgroundTemplate, FontTemplate, and IconTemplate. To choose a template based on the format condition type, create a template selector and assign it to the TableView.FormatConditionGeneratorTemplateSelector property:

public class FormatConditionSelector : DataTemplateSelector {

    public DataTemplate BackgroundTemplate { get; set; }
    public DataTemplate FontTemplate { get; set; }
    public DataTemplate IconTemplate { get; set; }

    public override DataTemplate SelectTemplate(object item, DependencyObject container) {
        FormattingRule rule = item as FormattingRule;
        if(rule == null) return null;
        switch(rule.Type) {
            case FormattingType.Font:
                return FontTemplate;
            case FormattingType.Background:
                return BackgroundTemplate;
            case FormattingType.Icon:
                return IconTemplate;
        }
        return null;
    }
}
<Window.Resources>
    <!-- ... -->
    <local:FormatConditionSelector x:Key="FormatConditionSelector" 
                                   BackgroundTemplate="{StaticResource BackgroundTemplate}" 
                                   FontTemplate="{StaticResource FontTemplate}" 
                                   IconTemplate="{StaticResource IconTemplate}"/>
</Window.Resources>
<dxg:GridControl ItemsSource="{Binding Orders}">
    <!-- ... -->
    <dxg:GridControl.View>
        <dxg:TableView FormatConditionsSource="{Binding Rules}"
                       FormatConditionGeneratorTemplateSelector="{StaticResource FormatConditionSelector}"/>
    </dxg:GridControl.View>
</dxg:GridControl>
See Also