wpfxamlmvvmmultibindingmultidatatrigger

Simplifying style.triggers with mulitibinding in WPF


In reviewing some code I wrote years ago, I have come across this trigger in my WPF style section. As can be seen, I am calling the MultiBinding Converter 7 times with the exact same references to Checkin, Checkout, and NotSeen to produce 7 different colors. This hits me as being awfully redundant and space consuming. There must be a better way.

Is there a way of accomplishing this with a shorter style? Also, is their a way of avoiding the MultiBinding Converter altogether in a MVVM framework? Could an attached behavior be used in place of this?

TIA

    <Style.Triggers>
            <!-- if checkout is null, then check for waiting time from the checkin value. Setter action occurs for DataTrigger Value -->
            <DataTrigger Value="1" >
                <DataTrigger.Binding>
                    <MultiBinding Converter="{StaticResource WaitStatus}">
                        <Binding Path="CheckIn" />
                        <Binding Path="CheckOut" />
                        <Binding Path="NotSeen" />
                    </MultiBinding>
                </DataTrigger.Binding>
                <Setter Property="Background" Value="{StaticResource VioletBrush}" />
            </DataTrigger>
            <DataTrigger Value="2" >
                <DataTrigger.Binding>
                    <MultiBinding Converter="{StaticResource WaitStatus}">
                        <Binding Path="CheckIn" />
                        <Binding Path="CheckOut" />
                        <Binding Path="NotSeen" />
                    </MultiBinding>
                </DataTrigger.Binding>
                <Setter Property="Background" Value="{StaticResource BlueBrush}" />
            </DataTrigger>
            <DataTrigger Value="3" >
                <DataTrigger.Binding>
                    <MultiBinding Converter="{StaticResource WaitStatus}">
                        <Binding Path="CheckIn" />
                        <Binding Path="CheckOut" />
                        <Binding Path="NotSeen" />
                    </MultiBinding>
                </DataTrigger.Binding>
                <Setter Property="Background" Value="{StaticResource TurquoiseBrush}" />
            </DataTrigger>
            <DataTrigger Value="4" >
                <DataTrigger.Binding>
                    <MultiBinding Converter="{StaticResource WaitStatus}">
                        <Binding Path="CheckIn" />
                        <Binding Path="CheckOut" />
                        <Binding Path="NotSeen" />
                    </MultiBinding>
                </DataTrigger.Binding>
                <Setter Property="Background" Value="{StaticResource GreenBrush}" />
            </DataTrigger>
            <DataTrigger Value="5" >
                <DataTrigger.Binding>
                    <MultiBinding Converter="{StaticResource WaitStatus}">
                        <Binding Path="CheckIn" />
                        <Binding Path="CheckOut" />
                        <Binding Path="NotSeen" />
                    </MultiBinding>
                </DataTrigger.Binding>
                <Setter Property="Background" Value="{StaticResource YellowBrush}" />
            </DataTrigger>
            <DataTrigger Value="6" >
                <DataTrigger.Binding>
                    <MultiBinding Converter="{StaticResource WaitStatus}">
                        <Binding Path="CheckIn" />
                        <Binding Path="CheckOut" />
                        <Binding Path="NotSeen" />
                    </MultiBinding>
                </DataTrigger.Binding>
                <Setter Property="Background" Value="{StaticResource OrangeBrush}" />
            </DataTrigger>
            <DataTrigger Value="7" >
                <DataTrigger.Binding>
                    <MultiBinding Converter="{StaticResource WaitStatus}">
                        <Binding Path="CheckIn" />
                        <Binding Path="CheckOut" />
                        <Binding Path="NotSeen" />
                    </MultiBinding>
                </DataTrigger.Binding>
                <Setter Property="Background" Value="{StaticResource RedBrush}" />
            </DataTrigger>
        </Style.Triggers>

Solution

  • First approach using Custom DataTrigger
    Create custom DataTrigger class where you programically define its binding but in code you set Setter.

    class DataTriggerBinding : DataTrigger
    {
        public DataTriggerBinding()
        {
            SetBinding();
        }
    
        private void SetBinding()
        {
            var multiBinding = new MultiBinding();
            multiBinding.Bindings.Add(new Binding("CheckIn"));
            multiBinding.Bindings.Add(new Binding("CheckOut"));
            multiBinding.Bindings.Add(new Binding("NotSeen"));
            multiBinding.Converter = new WaitStatus();
            this.Binding = multiBinding;
        }
    }
    

    XAML:

      <Label Content="{Binding Age}">
        <Label.Style>
            <Style TargetType="Label">
                <Style.Triggers>
                    <local:DataTriggerBinding Value="1">
                        <Setter Property="Foreground" Value="Red"/>
                    </local:DataTriggerBinding>
                </Style.Triggers>
            </Style>
        </Label.Style>
    </Label>
    

    Latter approach using attached behavior

    class DataTriggerBinding : DependencyObject
    {
        public static readonly DependencyProperty IsCustomBindingProperty = DependencyProperty.RegisterAttached(
            "CustomBinding", typeof(bool), typeof(DataTriggerBinding), new PropertyMetadata((x, y) =>
            {
                SetBinding((DataTrigger)x);
            }));
    
        public static void SetIsCustomBinding(DependencyObject element, bool value)
        {
            element.SetValue(IsCustomBindingProperty, value);
        }
    
        public static bool GetIsCustomBinding(DependencyObject element)
        {
            return (bool)element.GetValue(IsCustomBindingProperty);
        }
    
        private static void SetBinding(DataTrigger dataTrigger)
        {
            var multiBinding = new MultiBinding();
            multiBinding.Bindings.Add(new Binding("CheckIn"));
            multiBinding.Bindings.Add(new Binding("CheckOut"));
            multiBinding.Bindings.Add(new Binding("NotSeen"));
            multiBinding.Converter = new WaitStatus();
            dataTrigger.Binding = multiBinding;
        }
    }
    

    XAML:

        <DataTrigger local:DataTriggerBinding.IsCustomBinding="True" Value="1">
            <Setter Property="Foreground" Value="Red"/>
        </DataTrigger>