如何在WPF中为数据触发器提供多个条件?

193

我如何在WPF中为数据触发器提供多个条件?

4个回答

308

使用MultiDataTrigger类型。

<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>

29
在multiTrigger中是否有一种方法可以使用“或”语句,例如名字=“portland”或州名=“OR”? - jasonk
12
不确定MultiTrigger是否能够实现这一点。你可以为此定义两个触发器。 - Gishu
2
如果是一个简单的OR条件语句,您可以反转逻辑,使其变成AND。 |条件1 |条件2 | 结果 | |真 |真 | 真 | |真 |假 | 真 | |假 |真 | 真 | |假 |假 | 假 | 而不是检查任一/OR是true,当两个/AND为false时进行检查,并将默认值设置为true。 - WeSam Abdallah
3
您无法检查条件是否为 false。 - Jim Balter
5
你可以通过一个简单的转换器检查某个条件是否为假。 - Paul
2
@Paul,<Condition Value="False"> 怎么样? - r2d2

58

@jasonk - 如果你要使用“或”,那么请否定所有条件,因为(A and B) <=> ~(~A or ~B)

但如果你有除布尔值以外的值,请尝试使用类型转换器:

<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>

你可以根据需要使用 Convert 方法中的值来创建适合自己的条件。


3
啊,聪明之举将一切否定并翻转为“或”条件 :) - myermian
8
请您稍微详细地解释一下您的回答吗?我不确定如何使用它。conditionConverter是做什么用的?在这个例子中,我们如何将“Portland”和“OR”指定为我们的两个“or”选项? - DLeh
4
@cod3monk3y,你的链接已经失效了。 - Spidermain50

21

为了详细说明@serine的回答并阐述如何处理非平凡多值条件:我需要展示一个“变暗”遮罩在一个布尔条件NOT a AND (b OR NOT c)上。

背景是这是一个“多项选择”问题。如果用户选择错误答案,它将变为禁用(变暗且不能再次选择)。自动代理有能力专注于任何特定的选择以给出解释(边框突出显示)。当代理关注一个项目时,即使它被禁用,它也不应该变暗。所有未处于重点关注的项目都标记为取消关注,并应该变暗。

因此变暗的逻辑为:

NOT IsFocused AND (IsDefocused OR NOT Enabled)

为了实现这个逻辑,我创建了一个通用的IMultiValueConverter,名字(笨拙地)与我的逻辑匹配

// '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);
    }
    ...
}
在XAML中,我在<Style><Style.Triggers>资源中的MultiDataTrigger中使用了这个。
<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>

为了完整起见,我的转换器在 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>

12
我不认为转换器的目的是被用于这种方式。它们真正的作用是将值转换为显示用途。当变得如此复杂时,只需在视图模型上创建一个计算属性,以获得所需的结果。 - Martin Capodici
18
这个命名真是…… - Kelly Elton
19
请静默一会儿,缅怀编程曾经是一门工艺、代码优雅的时光。 - Fuzzy Logic

1

此答案仅适用于动画


如果您想要实现AND逻辑,应该使用MultiTrigger,以下是一个示例:

假设我们希望在属性Text=""(空字符串)IsKeyboardFocused="False"时执行某些操作,则您的代码应如下所示:

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

如果您想要实现 OR 逻辑,有几种方法可供选择,具体取决于您的需求:

第一种选项是使用多个触发器。
因此,假设您希望在 Text = "" IsKeyboardFocused="False" 的情况下执行某些操作,
那么您的代码应该类似于这样:

<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>

但是在这个问题中,如果我想要在文本不为空或者IsKeyboard="True"时执行某些操作,我该怎么办呢?这可以通过第二种方法实现:
回忆一下德摩根定律,它说的是!(!x && !y) = x || y。
所以我们将使用它来解决之前的问题,通过编写一个多触发器,当Text=""且IsKeyboard="True"时触发它,并在退出动作中执行我们的操作,就像这样:
<MultiTrigger>
    <MultiTrigger.Conditions>
        <Condition Property="Text" Value="" />
        <Condition Property="IsKeyboardFocused" Value="False" />
    </MultiTrigger.Conditions>
    <MultiTrigger.ExitActions>
        <!-- Do something here -->
    </MultiTrigger.ExitActions>
</MultiTrigger>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接