Como posso fornecer várias condições para acionamento de dados no WPF?

173

Como posso fornecer várias condições para acionamento de dados no WPF?

Sumeru Suresh
fonte

Respostas:

280

Use o tipo 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>
Gishu
fonte
28
Existe uma maneira de fazer uma declaração "OU" no multiTrigger. por exemplo, o name = "portland" ou o Estado = "ou"
jasonk
12
@jasonk - Não tenho certeza se você pode fazer isso com um MultiTrigger. Você pode definir dois gatilhos para isso ..
Gishu
2
Se for uma instrução OR simples, você pode reverter a lógica para que ela se transforme em um AND. | condição1 | condição2 | resultado | | true | true | verdadeiro | verdadeiro | falso | verdadeiro | falso | verdadeiro | verdadeiro | falso | falso | falso | em vez de verificar se / OU é verdadeiro, verifique quando ambos / AND são falsos e defina o padrão como verdadeiro.
WeSam Abdallah
3
@WeSamAbdallah Não é possível verificar se as condições são falsas.
Jim Balter
4
Você pode verificar se uma condição é falsa por um simples conversor.
Paulo
50

@jasonk - se você deseja ter "ou", negue todas as condições, pois (A e B) <=> ~ (~ A ou ~ B)

mas se você tiver valores diferentes de booleano, tente usar conversores de tipo:

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

você pode usar os valores no método Convert da maneira que desejar para produzir uma condição que combina com você.

serina
fonte
3
Ah, jogada inteligente para negar tudo e lançá-lo a uma condição OR :)
myermian
8
Você poderia expandir um pouco essa resposta? Não sei bem como usá-lo. O que conditionConverterfaz? Como estamos especificando "Portland" e "OR" como nossas duas oropções neste exemplo?
DLeh 30/05
4
@ cod3monk3y, seu link está quebrado.
Spidermain50
22

Para elaborar a resposta de @ serine e ilustrar o trabalho com uma condição com valores múltiplos não triviais: Eu precisava mostrar uma sobreposição de "escurecimento" em um item para a condição booleana NOT a AND (b OR NOT c).

Como pano de fundo, essa é uma pergunta de "múltipla escolha". Se o usuário escolher uma resposta errada, ela será desativada (esmaecida e não poderá ser selecionada novamente). Um agente automatizado tem a capacidade de se concentrar em qualquer opção específica para fornecer uma explicação (borda destacada). Quando o agente se concentra em um item, ele não deve ser esmaecido, mesmo se estiver desativado . Todos os itens que não estão focados são marcados como não focados e devem estar esmaecidos.

A lógica para escurecer é assim:

NOT IsFocused AND (IsDefocused OR NOT Enabled)

Para implementar essa lógica, criei um genérico IMultiValueConverterchamado (sem jeito) para corresponder à minha lógica

// '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);
    }
    ...
}

No XAML eu uso isso MultiDataTriggerem um <Style><Style.Triggers>recurso

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

E, para completar, meu conversor é definido em um 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>
cod3monk3y
fonte
11
Não acho que essa seja a intenção dos conversores serem usados ​​dessa maneira. Eles são realmente destinados à conversão de valores para exibição. Quando isso ficar complicado, basta criar uma propriedade calculada no modelo de exibição que fornece o que você precisa.
Martin Capodici
13
Esse nome embora
Kelly Elton
13
Reserve um momento de silêncio para lembrar quando a programação era um ofício e o código era elegante.
Fuzzy Logic
0

ESTA RESPOSTA É APENAS PARA ANIMAÇÕES


Se você deseja implementar a lógica AND, deve usar o MultiTrigger, aqui está um exemplo:

Suponha que desejemos executar algumas ações se a propriedade Text = "" (string vazia) AND IsKeyboardFocused = "False", então seu código deve ter a seguinte aparência:

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

Se você deseja implementar a lógica OR, existem duas maneiras, e isso depende do que você tenta fazer:

A primeira opção é usar vários gatilhos.
Então, suponha que você queira fazer algo se Text = "" OR IsKeyboardFocused = "False",
seu código deve ser algo como isto:

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


Mas o problema é o que farei se eu quiser fazer algo se o texto NÃO for nulo OU IsKeyboard = "True"? Isso pode ser alcançado pela segunda abordagem:
lembre - se da regra de De Morgan, que diz! (! X &&! Y) = x || y
Então, vamos usá-lo para resolver o problema anterior, escrevendo um disparador múltiplo que é disparado quando Text = "" e IsKeyboard = "True", e faremos nossas ações em EXIT ACTIONS , assim:

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