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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/905932/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 20:28:23  来源:igfitidea点击:

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

wpfdatatrigger

提问by Sumeru Suresh

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

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

回答by Gishu

Use MultiDataTriggertype

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

回答by serine

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

@jasonk - 如果你想要“或”然后否定所有条件,因为 (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.

您可以以任何您喜欢的方式使用 Convert 方法中的值来生成适合您的条件。

回答by cod3monk3y

To elaborate on @serine's answerand 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).

详细说明@serine 的答案并说明使用非平凡的多值条件:我需要在布尔条件的项目上显示“暗淡”叠加层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 focuson 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)

作为背景,这是一个“多项选择”问题。如果用户选择了错误的答案,它将被禁用(变暗且无法再次选择)。自动化代理能够专注于任何特定选择以给出解释(突出显示边界)。当代理专注于一个项目时,即使它被禁用也不应该变暗。所有未聚焦的项目都被标记为de-focused,并且应该变暗。

因此,调光的逻辑是:

NOT IsFocused AND (IsDefocused OR NOT Enabled)

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

为了实现这个逻辑,我创建了一个通用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);
    }
    ...
}

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

在 XAML 中,我MultiDataTrigger<Style><Style.Triggers>资源中使用它

<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

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

回答by Elyasaf755

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) ANDIsKeyboardFocused="False", then your code should look like the following:

这个答案仅适用于动画


如果你想实现 AND 逻辑,你应该使用 MultiTrigger,这是一个例子:

假设我们想要做一些动作,如果属性 Text="" (空字符串) ANDIsKeyboardFocused="False",然后您的代码应如下所示:

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

如果你想实现 OR 逻辑,有几种方法,这取决于你尝试做什么:

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

第一个选项是使用多个触发器。
因此,假设您想在 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>


But the problem in this is what will I do if i wanna do something if either Text ISN'T null ORIsKeyboard="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:


但这里的问题是,如果我想做某事,如果 Text ISN'T nullIsKeyboard="True" 该怎么办?这可以通过第二种方法来实现:
回忆德摩根的规则,即 !(!x && !y) = x || 是的
所以我们将使用它来解决前面的问题,通过编写一个多触发器,它在 Text="" 和 IsKeyboard="True" 时触发,我们将在EXIT ACTIONS 中执行我们的操作,如下所示:

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