What's the right way to trigger on multiple conditions in a WPF Style

26,860

Solution 1

Your assumptution is correct regarding the missing binding.

From MSDN MultiDataTrigger.Conditions:

For a MultiDataTrigger, each condition in the collection must set both the Binding and Value properties.

You can solve this using RelativeSource Self to refer yourself in the binding:

<MultiDataTrigger.Conditions>
    <Condition Binding="{Binding RelativeSource={RelativeSource Self},
         Path=IsSelected}" Value="True" />
    <Condition Binding="{Binding Path=IsInLiveMode}" Value="True" />
</MultiDataTrigger.Conditions>

Solution 2

You're using a MultiDataTrigger, which is still a DataTrigger and expects a binding

Switch Property="IsSelected" in your Condition to

<Condition Binding="{Binding IsSelected, RelativeSource={RelativeSource Self}}" 
           Value="True" />
Share:
26,860
Tony Vitabile
Author by

Tony Vitabile

Updated on July 09, 2022

Comments

  • Tony Vitabile
    Tony Vitabile almost 2 years

    My WPF application has a DataGrid control in it. I have a default custom style for the DataGridRow class which works well. However, for this one particular DataGrid on this one particular screen, I need a different custom style.

    The Items in each row have a bool property that, when set, I want to display that row with a different foreground and background color. However, when the row is selected AND when that property is set, I want a different foreground and background color to show that it's selected AND the property is set to true.

    Here's what I've tried:

    <Style TargetType="DataGridRow" x:Key="CameraStyle">
        <Setter Property="Foreground" Value="{DynamicResource TextForeground}" />
        <Setter Property="Background" Value="{DynamicResource DataBackground}" />
        <Style.Triggers>
            <MultiDataTrigger>
                <MultiDataTrigger.Conditions>
                    <Condition Property="IsSelected" Value="False" />
                    <Condition Binding="{Binding Path=IsInLiveMode}" Value="True" />
                </MultiDataTrigger.Conditions>
                <Setter Property="Foreground" Value="Red" />
                <Setter Property="Background" Value="Yellow" />
            </MultiDataTrigger>
            <MultiDataTrigger>
                <MultiDataTrigger.Conditions>
                    <Condition Property="IsSelected" Value="True" />
                    <Condition Binding="{Binding Path=IsInLiveMode}" Value="True" />
                </MultiDataTrigger.Conditions>
                <Setter Property="Background"  Value="DarkOrange" />
                <Setter Property="BorderBrush" Value="{DynamicResource DataBorder}" />
                <Setter Property="Foreground"  Value="DarkRed" />
            </MultiDataTrigger>
        </Style.Triggers>
    </Style>
    

    This gives me a "Binding must be non-null" error, which I think is happening because there is no Binding property on the first condition in the MultiDataTrigger.

    What is the correct way to write this in XAML?

    EDIT:

    After trying nemesv's & Rachel's answer, the code now compiles and runs. However, the colors I've chosen for the IsSelected = true and IsInLiveMode = true case are not showing up. Here's what I have now:

        <Style TargetType="DataGridRow" x:Key="CameraStyle">
            <Setter Property="Background" Value="{DynamicResource DataBackground}" />
            <Setter Property="Foreground" Value="{DynamicResource TextForeground}" />
            <Style.Triggers>
                <MultiDataTrigger>
                    <MultiDataTrigger.Conditions>
                        <Condition Binding="{Binding Path=IsSelected, RelativeSource={RelativeSource Self}}" Value="False" />
                        <Condition Binding="{Binding Path=IsInLiveMode}" Value="True" />
                    </MultiDataTrigger.Conditions>
                    <Setter Property="Background" Value="Yellow" />
                    <Setter Property="Foreground" Value="Red" />
                </MultiDataTrigger>
                <MultiDataTrigger>
                    <MultiDataTrigger.Conditions>
                        <Condition Binding="{Binding Path=IsSelected, RelativeSource={RelativeSource Self}}" Value="True" />
                        <Condition Binding="{Binding Path=IsInLiveMode}" Value="False" />
                    </MultiDataTrigger.Conditions>
                    <Setter Property="Background"  Value="{DynamicResource DataBackgroundSelected}" />
                    <Setter Property="BorderBrush" Value="{DynamicResource DataBorder}" />
                    <Setter Property="Foreground"  Value="{DynamicResource DataForegroundSelected}" />
                </MultiDataTrigger>
                <MultiDataTrigger>
                    <MultiDataTrigger.Conditions>
                        <Condition Binding="{Binding Path=IsSelected, RelativeSource={RelativeSource Self}}" Value="True" />
                        <Condition Binding="{Binding Path=IsInLiveMode}" Value="True" />
                    </MultiDataTrigger.Conditions>
                    <Setter Property="Background"  Value="DarkOrange" />
                    <Setter Property="BorderBrush" Value="{DynamicResource DataBorder}" />
                    <Setter Property="Foreground"  Value="DarkRed" />
                </MultiDataTrigger>
            </Style.Triggers>
        </Style>
    

    Any ideas on why the case in question isn't working?

  • Tony Vitabile
    Tony Vitabile over 11 years
    Rachel: I wish I could check off yours and @nemesv's answers as the correct answer, because you're both right. But nemesv did answer first, so he gets the checkmark.
  • Tony Vitabile
    Tony Vitabile over 11 years
    nemesv: Thanks, that at least doesn't throw any errors. There is still a problem. Please look at my edits to my original question.
  • Rachel
    Rachel over 11 years
    @TonyVitabile That's fine, I think his answer is better anyways because of the MSDN links, and already gave him a +1 for it :)