Comment puis-je fournir plusieurs conditions pour le déclencheur de données dans WPF?

173

Comment puis-je fournir plusieurs conditions pour le déclencheur de données dans WPF?

Sumeru Suresh
la source

Réponses:

280

Utiliser le type 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
la source
28
Existe-t-il un moyen de faire une instruction "OR" dans le multiTrigger. par exemple, le nom = "portland" OU l'état = "OU"
jasonk
12
@jasonk - Je ne sais pas si vous pouvez faire cela avec un MultiTrigger. Vous pouvez définir deux déclencheurs pour cela.
Gishu
2
S'il s'agit d'une simple instruction de condition OR, vous pouvez inverser la logique pour qu'elle se transforme en AND. | condition1 | condition2 | résultat | | vrai | vrai | vrai | | vrai | faux | vrai | | faux | vrai | vrai | | faux | faux | faux | au lieu de vérifier si / OU est vrai, vérifiez si les deux / AND sont faux et définissez la valeur par défaut sur true.
WeSam Abdallah
3
@WeSamAbdallah Vous ne pouvez pas vérifier si les conditions sont fausses.
Jim Balter
4
Vous pouvez vérifier qu'une condition est fausse par un simple convertisseur.
Paul
50

@jasonk - si vous voulez avoir "ou" alors annulez toutes les conditions depuis (A et B) <=> ~ (~ A ou ~ B)

mais si vous avez des valeurs autres que booléennes, essayez d'utiliser des convertisseurs de type:

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

vous pouvez utiliser les valeurs de la méthode Convert comme vous le souhaitez pour produire une condition qui vous convient.

sérine
la source
3
Ah, c'est un geste intelligent pour tout annuler et le retourner à une condition OU :)
myermian
8
Pourriez-vous s'il vous plaît développer un peu cette réponse? Je ne sais pas comment l'utiliser. Que fait le conditionConverter? Comment spécifions-nous "Portland" et "OU" comme nos deux oroptions dans cet exemple?
DLeh
4
@ cod3monk3y, votre lien est rompu.
Spidermain50
22

Pour élaborer sur la réponse de @ serine et illustrer le travail avec une condition multi-valeurs non triviale: j'avais besoin d'afficher une superposition "dim-out" sur un élément pour la condition booléenne NOT a AND (b OR NOT c).

Pour le contexte, il s'agit d'une question à «choix multiples». Si l'utilisateur choisit une mauvaise réponse, elle devient désactivée (estompée et ne peut pas être sélectionnée à nouveau). Un agent automatisé a la capacité de se concentrer sur n'importe quel choix particulier pour donner une explication (bordure en surbrillance). Lorsque l'agent se concentre sur un élément, il ne doit pas être grisé même s'il est désactivé . Tous les éléments qui ne sont pas focalisés sont marqués comme non focalisés et doivent être grisés.

La logique de la variation est donc:

NOT IsFocused AND (IsDefocused OR NOT Enabled)

Pour implémenter cette logique, j'ai fait un générique IMultiValueConverternommé (maladroitement) pour correspondre à ma logique

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

Dans le XAML, j'utilise ceci MultiDataTriggerdans une <Style><Style.Triggers>ressource

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

Et par souci d'exhaustivité, mon convertisseur est défini dans un 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
la source
11
Je ne pense pas que ce soit l'intention des convertisseurs d'être utilisé de cette façon. Ils sont vraiment destinés à convertir des valeurs pour l'affichage. Lorsque cela devient aussi compliqué, créez simplement une propriété calculée sur le modèle de vue qui vous donne ce dont vous avez besoin.
Martin Capodici
13
Cette dénomination cependant
Kelly Elton
13
Veuillez prendre un moment de silence pour vous rappeler quand la programmation était un métier et que le code était élégant.
Fuzzy Logic
0

CETTE RÉPONSE EST POUR LES ANIMATIONS UNIQUEMENT


Si vous souhaitez implémenter la logique AND, vous devez utiliser MultiTrigger, voici un exemple:

Supposons que nous voulions faire des actions si la propriété Text = "" (chaîne vide) AND IsKeyboardFocused = "False", alors votre code doit ressembler à ceci:

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

Si vous souhaitez implémenter la logique OR, il existe plusieurs façons, et cela dépend de ce que vous essayez de faire:

La première option consiste à utiliser plusieurs déclencheurs.
Donc, supposons que vous vouliez faire quelque chose si Text = "" OU IsKeyboardFocused = "False",
alors votre code devrait ressembler à ceci:

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


Mais le problème est que vais-je faire si je veux faire quelque chose si soit Text ISN'T null OU IsKeyboard = "True"? Ceci peut être réalisé par la deuxième approche:
rappelez la règle de De Morgan, qui dit! (! X &&! Y) = x || y.
Nous allons donc l'utiliser pour résoudre le problème précédent, en écrivant un déclencheur multiple qu'il est déclenché lorsque Text = "" et IsKeyboard = "True", et nous ferons nos actions dans EXIT ACTIONS , comme ceci:

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