How can I provide multiple conditions for data trigger in WPF?

WpfDatatrigger

Wpf Problem Overview


How can I provide multiple conditions for data trigger in WPF?

Wpf Solutions


Solution 1 - Wpf

Use MultiDataTrigger type

<Style TargetType="ListBoxItem">
    <Style.Triggers>
      <DataTrigger Binding="{Binding Path=State}" Value="WA">
        <Setter Property="Foreground" Value="Red" />
      </DataTrigger>    
      <MultiDataTrigger>
        <MultiDataTrigger.Conditions>
          <Condition Binding="{Binding Path=Name}" Value="Portland" />
          <Condition Binding="{Binding Path=State}" Value="OR" />
        </MultiDataTrigger.Conditions>
        <Setter Property="Background" Value="Cyan" />
      </MultiDataTrigger>
    </Style.Triggers>
  </Style>

Solution 2 - Wpf

@jasonk - if you want to have "or" then negate all conditions since (A and B) <=> ~(~A or ~B)

but if you have values other than boolean try using type converters:

<MultiDataTrigger.Conditions>
	<Condition Value="True">
		<Condition.Binding>
			<MultiBinding Converter="{StaticResource conditionConverter}">
				<Binding Path="Name" />
				<Binding Path="State" />
			</MultiBinding>
		</Condition.Binding>
		<Setter Property="Background" Value="Cyan" />
	</Condition>
</MultiDataTrigger.Conditions>

you can use the values in Convert method any way you like to produce a condition which suits you.

Solution 3 - Wpf

To elaborate on @serine's answer and illustrate working with non-trivial multi-valued condition: I had a need to show a "dim-out" overlay on an item for the boolean condition NOT a AND (b OR NOT c).

> For background, this is a "Multiple Choice" question. If the user picks a wrong answer it becomes disabled (dimmed out and cannot be selected again). An automated agent has the ability to focus on any particular choice to give an explanation (border highlighted). When the agent focuses on an item, it should not be dimmed out even if it is disabled. All items that are not in focused are marked de-focused, and should be dimmed out. > > The logic for dimming is thus: > > NOT IsFocused AND (IsDefocused OR NOT Enabled)

To implement this logic, I made a generic IMultiValueConverter named (awkwardly) to match my logic

// 'P' represents a parenthesis
//     !  a &&  ( b ||  !  c )
class NOT_a_AND_P_b_OR_NOT_c_P : IMultiValueConverter
{
    // redacted [...] for brevity
    public object Convert(object[] values, ...)
    {
        bool a = System.Convert.ToBoolean(values[0]);
        bool b = System.Convert.ToBoolean(values[1]);
        bool c = System.Convert.ToBoolean(values[2]);

        return !a && (b || !c);
    }
    ...
}

In the XAML I use this in a MultiDataTrigger in a <Style><Style.Triggers> resource

<MultiDataTrigger>
    <MultiDataTrigger.Conditions>
        <!-- when the equation is TRUE ... -->
        <Condition Value="True">
            <Condition.Binding>
                <MultiBinding Converter="{StaticResource NOT_a_AND_P_b_OR_NOT_c_P}">
                    <!-- NOT IsFocus AND ( IsDefocused OR NOT Enabled ) -->
                    <Binding Path="IsFocus"/>
                    <Binding Path="IsDefocused" />
                    <Binding Path="Enabled" />
                </MultiBinding>
            </Condition.Binding>
        </Condition>
    </MultiDataTrigger.Conditions>
    <MultiDataTrigger.Setters>
        <!-- ... show the 'dim-out' overlay -->
        <Setter Property="Visibility" Value="Visible" />
    </MultiDataTrigger.Setters>
</MultiDataTrigger>

And for completeness sake, my converter is defined in a ResourceDictionary

<ResourceDictionary xmlns:conv="clr-namespace:My.Converters" ...>
    <conv:NOT_a_AND_P_b_OR_NOT_c_P x:Key="NOT_a_AND_P_b_OR_NOT_c_P" />
</ResourceDictionary>

Solution 4 - Wpf

THIS ANSWER IS FOR ANIMATIONS ONLY


If you wanna implement the AND logic, you should use MultiTrigger, here is an example:

Suppose we want to do some actions if the property Text="" (empty string) AND IsKeyboardFocused="False", then your code should look like the following:

<MultiTrigger>
    <MultiTrigger.Conditions>
        <Condition Property="Text" Value="" />
        <Condition Property="IsKeyboardFocused" Value="False" />
    </MultiTrigger.Conditions>
        <MultiTrigger.EnterActions>
            <!-- Your actions here -->
        </MultiTrigger.EnterActions>
</MultiTrigger>

If you wanna implement the OR logic, there are couple of ways, and it depends on what you try to do:

The first option is to use multiple Triggers.
So, suppose you wanna do something if either Text="" OR IsKeyboardFocused="False",
then your code should look something like this:

<Trigger Property="IsEnabled" Value="false">
    <Setter Property="Opacity" TargetName="border" Value="0.56"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
    <Setter Property="BorderBrush" TargetName="border" 
            Value="{StaticResource TextBox.MouseOver.Border}"/>
</Trigger>


But the problem in this is what will I do if i wanna do something if either Text ISN'T null OR IsKeyboard="True"? This can be achieved by the second approach:
Recall De Morgan's rule, that says !(!x && !y) = x || y.
So we'll use it to solve the previous problem, by writing a multi trigger that it's triggered when Text="" and IsKeyboard="True", and we'll do our actions in EXIT ACTIONS, like this:

<MultiTrigger>
    <MultiTrigger.Conditions>
        <Condition Property="Text" Value="" />
        <Condition Property="IsKeyboardFocused" Value="False" />
    </MultiTrigger.Conditions>
    <MultiTrigger.ExitActions>
        <!-- Do something here -->
    </MultiTrigger.ExitActions>
</MultiTrigger>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSumeru SureshView Question on Stackoverflow
Solution 1 - WpfGishuView Answer on Stackoverflow
Solution 2 - WpfserineView Answer on Stackoverflow
Solution 3 - Wpfcod3monk3yView Answer on Stackoverflow
Solution 4 - WpfElyasaf755View Answer on Stackoverflow