Jak mogę podać wiele warunków dla wyzwalacza danych w WPF?

173

Jak mogę podać wiele warunków dla wyzwalacza danych w WPF?

Sumeru Suresh
źródło

Odpowiedzi:

280

Użyj typu 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
źródło
28
Czy istnieje sposób na wykonanie instrukcji „OR” w multiTrigger. np. nazwa = „portland” LUB stan = „LUB”
jasonk
12
@jasonk - Nie jestem pewien, czy możesz to zrobić za pomocą MultiTrigger. Możesz zdefiniować dwa wyzwalacze.
Gishu
2
Jeśli jest to prosta instrukcja warunkowa OR, możesz odwrócić tę logikę, aby zmieniła się w AND. | warunek1 | warunek2 | wynik | | prawda | prawda | prawda | | prawda | fałsz | prawda | | false | true | prawda | | false | false | fałsz | zamiast sprawdzać, czy oba / OR są prawdziwe, sprawdź, czy oba / AND są fałszywe i ustaw wartość domyślną na true.
WeSam Abdallah
3
@WeSamAbdallah Nie możesz sprawdzić, czy warunki są fałszywe.
Jim Balter
4
Możesz sprawdzić, czy warunek jest fałszywy za pomocą prostego konwertera.
Paul,
50

@jasonk - jeśli chcesz mieć „lub”, zaneguj wszystkie warunki od (A i B) <=> ~ (~ A lub ~ B)

ale jeśli masz wartości inne niż logiczne, spróbuj użyć konwerterów typów:

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

możesz użyć wartości w metodzie Convert w dowolny sposób, aby stworzyć warunek, który Ci odpowiada.

seryna
źródło
3
Ach, sprytny ruch, aby zanegować wszystko i
zmienić
8
Czy mógłbyś trochę rozwinąć tę odpowiedź? Nie wiem, jak go używać. Co to conditionConverterrobi? W jaki sposób określamy „Portland” i „OR” jako dwie oropcje w tym przykładzie?
DLeh
4
@ cod3monk3y, Twój link jest uszkodzony.
Spidermain50
22

Aby rozwinąć odpowiedź @ serine i zilustrować pracę z nietrywialnym warunkiem wielowartościowym: Musiałem pokazać nakładkę „dim-out” na elemencie dla warunku boolowskiego NOT a AND (b OR NOT c).

W tle jest to pytanie „wielokrotnego wyboru”. Jeśli użytkownik wybierze złą odpowiedź, zostaje ona wyłączona (wygaszona i nie można jej ponownie wybrać). Automatyczny agent może skupić się na każdym konkretnym wyborze, aby udzielić wyjaśnienia (obramowanie podświetlone). Gdy agent skupia się na elemencie, nie powinien być wygaszany, nawet jeśli jest wyłączony . Wszystkie elementy, które nie są skupione, są oznaczone jako nieostre i powinny być wygaszone.

Logika ściemniania jest następująca:

NOT IsFocused AND (IsDefocused OR NOT Enabled)

Aby zaimplementować tę logikę, stworzyłem rodzaj o IMultiValueConverternazwie (niezręcznie), aby pasował do mojej logiki

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

W XAML używam tego w sposób MultiDataTriggerw <Style><Style.Triggers>zasobie

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

Ze względu na kompletność mój konwerter jest zdefiniowany w pliku 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
źródło
11
Nie sądzę, aby taki był zamiar konwerterów, które mają być używane w ten sposób. Są tak naprawdę przeznaczone do konwersji wartości do wyświetlenia. Kiedy robi się to skomplikowane, po prostu utwórz obliczoną właściwość w modelu widoku, która zapewnia to, czego potrzebujesz.
Martin Capodici,
13
Jednak to nazewnictwo
Kelly Elton
13
Poświęć chwilę ciszy, aby przypomnieć sobie, kiedy programowanie było rzemiosłem, a kod był elegancki.
Logika rozmyta
0

TA ODPOWIEDŹ DOTYCZY WYŁĄCZNIE ANIMACJI


Jeśli chcesz zaimplementować logikę AND, powinieneś użyć MultiTrigger, oto przykład:

Załóżmy, że chcemy wykonać jakieś akcje, jeśli właściwość Text = "" (pusty ciąg) AND IsKeyboardFocused = "False", a następnie Twój kod powinien wyglądać następująco:

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

Jeśli chcesz wdrożyć logikę OR, istnieje kilka sposobów i zależy to od tego, co próbujesz zrobić:

Pierwszą opcją jest użycie wielu wyzwalaczy.
Więc załóżmy, że chcesz coś zrobić, jeśli albo Text = "" LUB IsKeyboardFocused = "False",
wtedy Twój kod powinien wyglądać mniej więcej tak:

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


Ale problem polega na tym, co mam zrobić, jeśli chcę coś zrobić, jeśli albo tekst NIE JEST null, LUB IsKeyboard = "True"? Można to osiągnąć poprzez drugie podejście:
Przypomnij sobie regułę De Morgana, która mówi! (! X &&! Y) = x || y.
Więc użyjemy go do rozwiązania poprzedniego problemu, pisząc wyzwalacz wielokrotny, który jest wyzwalany, gdy Text = "" i IsKeyboard = "True", a nasze działania wykonamy w EXIT ACTIONS , na przykład:

<MultiTrigger>
    <MultiTrigger.Conditions>
        <Condition Property="Text" Value="" />
        <Condition Property="IsKeyboardFocused" Value="False" />
    </MultiTrigger.Conditions>
    <MultiTrigger.ExitActions>
        <!-- Do something here -->
    </MultiTrigger.ExitActions>
</MultiTrigger>
Elyasaf755
źródło