Wie kann ich mehrere Bedingungen für den Datenauslöser in WPF bereitstellen?

173

Wie kann ich mehrere Bedingungen für den Datenauslöser in WPF bereitstellen?

Sumeru Suresh
quelle

Antworten:

280

Verwenden Sie den Typ 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
quelle
28
Gibt es eine Möglichkeit, eine "ODER" -Anweisung im MultiTrigger auszuführen? zB der Name = "Portland" ODER der Staat = "ODER"
Jason
12
@jasonk - Ich bin mir nicht sicher, ob Sie das mit einem MultiTrigger tun können. Sie können zwei Auslöser dafür definieren ..
Gishu
2
Wenn es sich um eine einfache ODER-Bedingungsanweisung handelt, können Sie die Logik umkehren, sodass sie zu einem UND wird. | Bedingung1 | Bedingung2 | Ergebnis | | wahr | wahr | wahr | | wahr | falsch | wahr | | false | true | wahr | | false | false | false | Anstatt zu prüfen, ob entweder / OR wahr ist, prüfen Sie, ob beide / AND falsch sind, und setzen Sie den Standardwert auf true.
WeSam Abdallah
3
@WeSamAbdallah Sie können nicht überprüfen, ob die Bedingungen falsch sind.
Jim Balter
4
Sie können mit einem einfachen Konverter überprüfen, ob eine Bedingung falsch ist.
Paul
50

@jasonk - Wenn Sie "oder" haben möchten, negieren Sie alle Bedingungen seit (A und B) <=> ~ (~ A oder ~ B)

Wenn Sie jedoch andere Werte als Boolesche Werte haben, verwenden Sie Typkonverter:

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

Sie können die Werte in der Convert-Methode beliebig verwenden, um eine Bedingung zu erstellen, die zu Ihnen passt.

Serin
quelle
3
Ah, kluger Schachzug, um alles zu negieren und in einen OP-Zustand zu
versetzen
8
Könnten Sie diese Antwort bitte etwas näher erläutern? Ich bin mir nicht sicher, wie ich es verwenden soll. Was macht das conditionConverter? Wie geben wir orin diesem Beispiel "Portland" und "OR" als unsere beiden Optionen an?
DLeh
4
@ cod3monk3y, dein Link ist kaputt.
Spidermain50
22

Um die Antwort von @ serine zu erläutern und die Arbeit mit einer nicht trivialen mehrwertigen Bedingung zu veranschaulichen: Ich musste ein "Dim-Out" -Overlay für ein Element für die boolesche Bedingung anzeigen NOT a AND (b OR NOT c).

Als Hintergrund ist dies eine "Multiple Choice" -Frage. Wenn der Benutzer eine falsche Antwort auswählt, wird diese deaktiviert (abgeblendet und kann nicht erneut ausgewählt werden). Ein automatisierter Agent kann sich auf eine bestimmte Auswahl konzentrieren, um eine Erklärung abzugeben (Rand hervorgehoben). Wenn sich der Agent auf ein Element konzentriert, sollte es auch dann nicht abgeblendet werden , wenn es deaktiviert ist . Alle Elemente , die nicht in fokussierter sind markiert defokussierte und sollte abgeblendet werden.

Die Logik zum Dimmen lautet also:

NOT IsFocused AND (IsDefocused OR NOT Enabled)

Um diese Logik zu implementieren, habe ich einen generischen IMultiValueConverterNamen (umständlich) erstellt, der meiner Logik entspricht

// '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 der XAML verwende ich dies in einer MultiDataTriggerin einer <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>

Der Vollständigkeit halber ist mein Konverter in a definiert 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
quelle
11
Ich denke nicht, dass dies die Absicht von Konvertern ist, auf diese Weise verwendet zu werden. Sie sind wirklich dazu gedacht, Werte für die Anzeige zu konvertieren. Wenn es so kompliziert wird, erstellen Sie einfach eine berechnete Eigenschaft im Ansichtsmodell, die Ihnen das bietet, was Sie benötigen.
Martin Capodici
13
Diese Benennung jedoch
Kelly Elton
13
Bitte nehmen Sie sich einen Moment Zeit zum Schweigen, um sich daran zu erinnern, wann das Programmieren ein Handwerk war und der Code elegant.
Fuzzy Logic
0

DIESE ANTWORT IST NUR FÜR ANIMATIONEN


Wenn Sie die AND-Logik implementieren möchten, sollten Sie MultiTrigger verwenden. Hier ein Beispiel:

Angenommen, wir möchten einige Aktionen ausführen, wenn die Eigenschaft Text = "" (leere Zeichenfolge) AND IsKeyboardFocused = "False" ist Ihr Code sollte wie folgt aussehen:

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

Wenn Sie die ODER-Logik implementieren möchten, gibt es mehrere Möglichkeiten, und dies hängt davon ab, was Sie versuchen:

Die erste Option besteht darin, mehrere Trigger zu verwenden.
Angenommen, Sie möchten etwas tun, wenn entweder Text = "" ODER IsKeyboardFocused = "False",
dann sollte Ihr Code ungefähr so aussehen:

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


Aber das Problem dabei ist , was ich tun , wenn ich etwas tun möchte , wenn entweder Text nicht null OR IsKeyboard = „True“? Dies kann durch den zweiten Ansatz erreicht werden:
Erinnern Sie sich an die Regel von De Morgan, die besagt! (! X &&! Y) = x || y.
Wir werden es also verwenden, um das vorherige Problem zu lösen, indem wir einen Multi-Trigger schreiben, der ausgelöst wird, wenn Text = "" und IsKeyboard = "True", und wir werden unsere Aktionen in EXIT ACTIONS wie folgt ausführen :

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