¿Cómo puedo proporcionar múltiples condiciones para la activación de datos en WPF?

173

¿Cómo puedo proporcionar múltiples condiciones para la activación de datos en WPF?

Sumeru Suresh
fuente

Respuestas:

280

Utilice el 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
fuente
28
¿Hay alguna manera de hacer una declaración "OR" en el MultiTrigger? por ejemplo, el nombre = "portland" O el estado = "O"
jasonk
12
@jasonk: no estoy seguro de poder hacerlo con un MultiTrigger. Puede definir dos desencadenantes para eso ..
Gishu
2
Si se trata de una simple declaración de condición OR, puede invertir la lógica para que se convierta en AND. | condición1 | condición2 | resultado | | verdadero | verdadero | cierto | | verdadero | falso | cierto | | falso | verdadero | cierto | | falso | falso | falso | en lugar de verificar si / OR es verdadero, verifique si ambos / AND son falsos y establezca el valor predeterminado en verdadero.
WeSam Abdallah
3
@WeSamAbdallah No puede verificar si las condiciones son falsas.
Jim Balter
44
Puede verificar si una condición es falsa con un simple convertidor.
Paul
50

@jasonk: si desea tener "o", niegue todas las condiciones desde (A y B) <=> ~ (~ A o ~ B)

pero si tiene valores distintos a booleanos, intente usar convertidores 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>

puede usar los valores en el método Convertir de la forma que desee para producir una condición que le convenga.

serina
fuente
3
Ah, movimiento inteligente para negar todo y
cambiarlo
8
¿Podría por favor ampliar un poco esta respuesta? No estoy seguro de cómo usarlo. ¿Qué hace el conditionConverter? ¿Cómo estamos especificando "Portland" y "OR" como nuestras dos oropciones en este ejemplo?
DLeh
44
@ cod3monk3y, tu enlace está roto.
Spidermain50
22

Para elaborar la respuesta de @ serine e ilustrar el trabajo con una condición de valores múltiples no trivial: necesitaba mostrar una superposición de "atenuación" en un elemento para la condición booleana NOT a AND (b OR NOT c).

Para el fondo, esta es una pregunta de "opción múltiple". Si el usuario elige una respuesta incorrecta, se desactiva (se atenúa y no se puede volver a seleccionar). Un agente automatizado tiene la capacidad de enfocarse en cualquier opción particular para dar una explicación (borde resaltado). Cuando el agente se centra en un elemento, no debe atenuarse incluso si está desactivado . Todos los artículos que no están en centrado están marcados de-centrado , y deben ser atenuadas a cabo.

La lógica para la atenuación es así:

NOT IsFocused AND (IsDefocused OR NOT Enabled)

Para implementar esta lógica, hice un IMultiValueConverternombre genérico (torpemente) para que coincida con mi 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);
    }
    ...
}

En XAML, uso esto MultiDataTriggeren un <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>

Y para completar, mi convertidor se define en 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
fuente
11
No creo que esta sea la intención de los convertidores para ser utilizados de esta manera. Realmente están destinados a convertir valores para mostrar. Cuando esto se complique, simplemente cree una propiedad calculada en el modelo de vista que le brinde lo que necesita.
Martin Capodici
13
Sin embargo
Kelly Elton el
13
Tómese un momento de silencio para recordar cuándo la programación era un oficio y el código era elegante.
Fuzzy Logic
0

ESTA RESPUESTA ES SOLO PARA ANIMACIONES


Si desea implementar la lógica AND, debe usar MultiTrigger, aquí hay un ejemplo:

supongamos que queremos hacer algunas acciones si la propiedad Text = "" (cadena vacía) AND IsKeyboardFocused = "False", entonces su código debería tener el siguiente aspecto:

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

Si desea implementar la lógica OR, hay un par de formas, y depende de lo que intente hacer:

La primera opción es usar múltiples disparadores.
Entonces, suponga que quiere hacer algo si Text = "" OR IsKeyboardFocused = "False",
entonces su código debería verse así:

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


Pero el problema en esto es ¿qué haré si quiero hacer algo si Text ISN'T null OR IsKeyboard = "True"? Esto se puede lograr con el segundo enfoque:
recuerde la regla de De Morgan, que dice! (! X &&! Y) = x || y.
Entonces lo usaremos para resolver el problema anterior, escribiendo un disparador múltiple que se dispara cuando Text = "" e IsKeyboard = "True", y haremos nuestras acciones en ACCIONES DE SALIDA , como esta:

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