Desencadenadores
Los desencadenadores de .NET Multi-platform App UI (.NET MAUI) te permiten expresar acciones de forma declarativa en XAML que cambian la apariencia de los controles basados en eventos o cambios de datos. Además, los desencadenadores de estado, que son un grupo especializado de desencadenadores, definen cuándo se debe aplicar la clase VisualState.
Puedes asignar un desencadenador directamente a la colección Triggers de un control, o agregarlo a un diccionario de recursos a nivel de página o de aplicación para que se aplique a varios controles.
Desencadenadores de propiedad
Trigger representa un desencadenador que aplica valores de propiedad o realiza acciones cuando la propiedad especificada cumple una condición especificada.
El siguiente ejemplo muestra un Trigger que cambia un color de fondo Entry cuando recibe un enfoque:
<Entry Placeholder="Enter name">
<Entry.Triggers>
<Trigger TargetType="Entry"
Property="IsFocused"
Value="True">
<Setter Property="BackgroundColor"
Value="Yellow" />
<!-- Multiple Setter elements are allowed -->
</Trigger>
</Entry.Triggers>
</Entry>
La declaración del desencadenador especifica lo siguiente:
- TargetType: el tipo de control al que se aplica el desencadenador.
- Property: la propiedad en el control que se supervisa.
- Value: el valor, cuando se produce para la propiedad supervisada, que causa que el desencadenador se active.
- Setter: una colección de elementos Setter que se aplican cuando se cumple la condición del desencadenador.
Además, se pueden especificar colecciones opcionales EnterActions y ExitActions. Para obtener más información, consulta EnterActions y ExitActions.
Aplicación de un desencadenador con un estilo
Los desencadenadores también se pueden agregar a una declaración Style en un control, en una página o una aplicación ResourceDictionary. El siguiente ejemplo declara un estilo implícito para todos los controles Entry de la página:
<ContentPage.Resources>
<Style TargetType="Entry">
<Style.Triggers>
<Trigger TargetType="Entry"
Property="IsFocused"
Value="True">
<Setter Property="BackgroundColor"
Value="Yellow" />
<!-- Multiple Setter elements are allowed -->
</Trigger>
</Style.Triggers>
</Style>
</ContentPage.Resources>
Desencadenadores de datos
DataTrigger representa un desencadenador que aplica valores de propiedad o realiza acciones cuando los datos dependientes cumplen una condición especificada. La extensión de marcado Binding
se usa para supervisar la condición especificada.
El siguiente ejemplo muestra DataTrigger que deshabilita Button cuando Entry está vacío:
<Entry x:Name="entry"
Text=""
Placeholder="Enter text" />
<Button Text="Save">
<Button.Triggers>
<DataTrigger TargetType="Button"
Binding="{Binding Source={x:Reference entry},
Path=Text.Length}"
Value="0">
<Setter Property="IsEnabled"
Value="False" />
<!-- Multiple Setter elements are allowed -->
</DataTrigger>
</Button.Triggers>
</Button>
En este ejemplo, cuando la longitud de Entry es cero, se activa el desencadenador.
Sugerencia
Al evaluar Path=Text.Length
proporciona siempre un valor predeterminado para la propiedad de destino (por ejemplo, Text=""
) porque de lo contrario será null
y el desencadenador no funcionará como esperas.
Además, se pueden especificar colecciones opcionales EnterActions y ExitActions. Para obtener más información, consulta EnterActions y ExitActions.
Desencadenadores de eventos
EventTrigger representa un desencadenador que aplica un conjunto de acciones en respuesta a un evento. A diferencia de Trigger, EventTrigger no tiene ningún concepto de terminación de estado, por lo que las acciones no se desharán una vez que la condición que elevó el evento ya no sea cierta.
EventTrigger solo requiere que se establezca una propiedad Event
:
<EventTrigger Event="TextChanged">
<local:NumericValidationTriggerAction />
</EventTrigger>
En este ejemplo, no hay elementos Setter. En su lugar, hay un objeto NumericalValidationTriggerAction
.
Nota:
Los desencadenadores de eventos no son compatibles con EnterActions y ExitActions.
Una implementación de acción de desencadenador debe:
- Implementar la clase genérica TriggerAction<T>, con el parámetro genérico correspondiente al tipo de control al que se va a aplicar el desencadenador. Puedes usar clases como VisualElement para escribir acciones de desencadenador que funcionen con una serie de controles, o especificar un tipo de control como Entry.
- Invalide el método Invoke . Se llama a este método siempre que se produce el efecto desencadenante.
- Opcionalmente, exponer propiedades que se pueden establecer en el XAML cuando se declara el desencadenador.
En el ejemplo siguiente se muestra la clase NumericValidationTriggerAction
:
public class NumericValidationTriggerAction : TriggerAction<Entry>
{
protected override void Invoke(Entry entry)
{
double result;
bool isValid = Double.TryParse(entry.Text, out result);
entry.TextColor = isValid ? Colors.Black : Colors.Red;
}
}
Advertencia
Ten cuidado al compartir desencadenadores en ResourceDictionary. Se compartirá una instancia entre los controles, de modo que cualquier estado que se configure una vez se aplicará a todos ellos.
Multi-desencadenadores
MultiTrigger representa un desencadenador que aplica valores de propiedad, o realiza acciones, cuando se cumplen una serie de condiciones. Todas las condiciones deben ser verdaderas antes de que se apliquen los objetos Setter.
En el ejemplo siguiente se muestra MultiTrigger que se enlaza a dos objetos Entry:
<Entry x:Name="email"
Text="" />
<Entry x:Name="phone"
Text="" />
<Button Text="Save">
<Button.Triggers>
<MultiTrigger TargetType="Button">
<MultiTrigger.Conditions>
<BindingCondition Binding="{Binding Source={x:Reference email},
Path=Text.Length}"
Value="0" />
<BindingCondition Binding="{Binding Source={x:Reference phone},
Path=Text.Length}"
Value="0" />
</MultiTrigger.Conditions>
<Setter Property="IsEnabled" Value="False" />
<!-- multiple Setter elements are allowed -->
</MultiTrigger>
</Button.Triggers>
</Button>
Además, la colección MultiTrigger.Conditions
también puede contener objetos PropertyCondition:
<PropertyCondition Property="Text"
Value="OK" />
EnterActions y ExitActions
Otra forma de implementar cambios cuando se produce un desencadenador es mediante la especificación de las colecciones EnterActions y ExitActions y la creación de implementaciones TriggerAction<T>.
La colección EnterActions, de tipo IList<TriggerAction>
, se usa para definir una colección que se invocará cuando se cumpla la condición del desencadenador. La colección ExitActions, de tipo IList<TriggerAction>
, se usa para definir una colección que se invocará cuando ya no se cumpla la condición del desencadenador.
Nota:
La clase EventTrigger omite los objetos TriggerAction definidos en las colecciones EnterActions y ExitActions.
En el ejemplo siguiente se muestra un desencadenador de propiedad que especifica un EnterAction
y un ExitAction
:
<Entry Placeholder="Enter job title">
<Entry.Triggers>
<Trigger TargetType="Entry"
Property="Entry.IsFocused"
Value="True">
<Trigger.EnterActions>
<local:FadeTriggerAction StartsFrom="0" />
</Trigger.EnterActions>
<Trigger.ExitActions>
<local:FadeTriggerAction StartsFrom="1" />
</Trigger.ExitActions>
</Trigger>
</Entry.Triggers>
</Entry>
Una implementación de acción de desencadenador debe:
- Implementar la clase genérica TriggerAction<T>, con el parámetro genérico correspondiente al tipo de control al que se va a aplicar el desencadenador. Puedes usar clases como VisualElement para escribir acciones de desencadenador que funcionen con una serie de controles, o especificar un tipo de control como Entry.
- Invalide el método Invoke . Se llama a este método siempre que se produce el efecto desencadenante.
- Opcionalmente, exponer propiedades que se pueden establecer en el XAML cuando se declara el desencadenador.
En el ejemplo siguiente se muestra la clase FadeTriggerAction
:
public class FadeTriggerAction : TriggerAction<VisualElement>
{
public int StartsFrom { get; set; }
protected override void Invoke(VisualElement sender)
{
sender.Animate("FadeTriggerAction", new Animation((d) =>
{
var val = StartsFrom == 1 ? d : 1 - d;
sender.BackgroundColor = Color.FromRgb(1, val, 1);
}),
length: 1000, // milliseconds
easing: Easing.Linear);
}
}
Nota:
Puedes proporcionar objetos EnterActions y ExitActions, así como objetos Setter en un desencadenador, pero ten en cuenta que se llama a los objetos Setter de inmediato (no se espera a que se completen EnterAction
o ExitAction
).
Desencadenadores de estado
Los desencadenadores de estado son un conjunto especializado de desencadenadores que definen las condiciones en las que se debe aplicar VisualState.
Los desencadenadores de estado se agregan a la colección StateTriggers de una clase VisualState. Esta colección puede contener un único desencadenador de estado o varios desencadenadores de estado. Se aplicará una clase VisualState cuando cualquier desencadenador de estado de la colección esté activo.
Al usar desencadenadores de estado para controlar los estados visuales, .NET MAUI usa las siguientes reglas de prioridad para determinar qué desencadenador (y VisualState correspondiente) se activará:
- Cualquier desencadenador derivado de StateTriggerBase.
- Una clase AdaptiveTrigger activada debido a que se cumple la condición MinWindowWidth.
- Una clase AdaptiveTrigger activada debido a que se cumple la condición MinWindowHeight.
Si hay varios desencadenadores activos simultáneamente (por ejemplo, dos desencadenadores personalizados), tiene prioridad el primer desencadenador declarado en el marcado.
Nota:
Los desencadenadores de estado se pueden establecer en una clase Style o directamente en los elementos.
Para obtener más información sobre los estados visuales, consulta Estados visuales.
Desencadenador de estado
La clase StateTrigger, que se deriva de la clase StateTriggerBase, tiene una propiedad enlazable IsActive. Un elemento StateTrigger desencadena un cambio de VisualState cuando cambia el valor de la propiedad IsActive.
La clase StateTriggerBase, que es la clase base de todos los desencadenadores de estado, tiene una propiedad IsActive y un evento IsActiveChanged. Este evento se desencadena cuando se produce un cambio de VisualState. Además, la clase StateTriggerBase tiene métodos OnAttached y OnDetached que se pueden invalidar.
Importante
La propiedad enlazable StateTrigger.IsActive
oculta la propiedad StateTriggerBase.IsActive
heredada.
En el siguiente ejemplo de XAML, se muestra una clase Style que incluye objetos StateTrigger:
<Style TargetType="Grid">
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup>
<VisualState x:Name="Checked">
<VisualState.StateTriggers>
<StateTrigger IsActive="{Binding IsToggled}"
IsActiveChanged="OnCheckedStateIsActiveChanged" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Property="BackgroundColor"
Value="Black" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Unchecked">
<VisualState.StateTriggers>
<StateTrigger IsActive="{Binding IsToggled, Converter={StaticResource inverseBooleanConverter}}"
IsActiveChanged="OnUncheckedStateIsActiveChanged" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Property="BackgroundColor"
Value="White" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
En este ejemplo, la clase Style implícita se destina a objetos Grid. Cuando la propiedad IsToggled
del objeto enlazado es true
, el color de fondo de Grid se establece en negro. Cuando la propiedad IsToggled
del objeto enlazado se convierte en false
, se desencadena un cambio de VisualState, y el color de fondo de Grid cambia a blanco.
Además, cada vez que cambia VisualState, se desencadena el evento IsActiveChanged para VisualState. Cada VisualState registra un controlador de eventos para este evento:
void OnCheckedStateIsActiveChanged(object sender, EventArgs e)
{
StateTriggerBase stateTrigger = sender as StateTriggerBase;
Console.WriteLine($"Checked state active: {stateTrigger.IsActive}");
}
void OnUncheckedStateIsActiveChanged(object sender, EventArgs e)
{
StateTriggerBase stateTrigger = sender as StateTriggerBase;
Console.WriteLine($"Unchecked state active: {stateTrigger.IsActive}");
}
En este ejemplo, cuando se desencadena un controlador para el evento IsActiveChanged, el controlador indica si VisualState está activo o no. Por ejemplo, los mensajes siguientes aparecen en la ventana de la consola cuando cambian del estado visual Checked
al estado visual Unchecked
:
Checked state active: False
Unchecked state active: True
Nota:
Para crear desencadenadores de estado personalizados, derive de la clase StateTriggerBase e invalide los métodos OnAttached
y OnDetached
para realizar cualquier registro y limpieza necesarios.
Desencadenador adaptable
Una clase AdaptiveTrigger desencadena un cambio de VisualState cuando la ventana tiene un alto o un ancho especificado. Este desencadenador tiene dos propiedades enlazables:
- MinWindowHeight, de tipo
double
, que indica la altura mínima de la ventana a la que debe aplicarse VisualState. - MinWindowWidth, de tipo
double
, que indica la anchura mínima de la ventana a la que debe aplicarse VisualState.
Nota:
El elemento AdaptiveTrigger deriva de la clase StateTriggerBase y, por tanto, puede adjuntar un controlador de eventos al evento IsActiveChanged
.
En el siguiente ejemplo de XAML, se muestra una clase Style que incluye objetos AdaptiveTrigger:
<Style TargetType="StackLayout">
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup>
<VisualState x:Name="Vertical">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Property="Orientation"
Value="Vertical" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Horizontal">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="800" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Property="Orientation"
Value="Horizontal" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
En este ejemplo, la clase Style implícita se destina a objetos StackLayout. Cuando el ancho de la ventana tiene entre 0 y 800 unidades independientes del dispositivo, los objetos StackLayout a los que se aplica la clase Style tendrán una orientación vertical. Cuando el ancho de la ventana es >= que 800 unidades independientes del dispositivo, se desencadena el cambio de VisualState y la orientación de StackLayout cambia a horizontal:
Las propiedades MinWindowHeight y MinWindowWidth se pueden utilizar de forma independiente o combinándolas entre sí. En el siguiente ejemplo de XAML se muestra la configuración de ambas propiedades:
<AdaptiveTrigger MinWindowWidth="800"
MinWindowHeight="1200"/>
En este ejemplo, AdaptiveTrigger indica que VisualState correspondiente se aplicará cuando el ancho de la ventana actual es >= 800 unidades independientes del dispositivo y el alto de la ventana actual es >= 1200 unidades independientes del dispositivo.
Comparación del desencadenador de estado
CompareStateTrigger desencadena un cambio de VisualState cuando una propiedad es igual a un valor específico. Este desencadenador tiene dos propiedades enlazables:
- Property, de tipo
object
, que indica la propiedad comparada por el desencadenador. - Value, de tipo
object
, que indica el valor al que debe aplicarse VisualState.
Nota:
El elemento CompareStateTrigger deriva de la clase StateTriggerBase y, por tanto, puede adjuntar un controlador de eventos al evento IsActiveChanged
.
En el siguiente ejemplo de XAML, se muestra una clase Style que incluye objetos CompareStateTrigger:
<Style TargetType="Grid">
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup>
<VisualState x:Name="Checked">
<VisualState.StateTriggers>
<CompareStateTrigger Property="{Binding Source={x:Reference checkBox}, Path=IsChecked}"
Value="True" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Property="BackgroundColor"
Value="Black" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Unchecked">
<VisualState.StateTriggers>
<CompareStateTrigger Property="{Binding Source={x:Reference checkBox}, Path=IsChecked}"
Value="False" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Property="BackgroundColor"
Value="White" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
...
<Grid>
<Frame BackgroundColor="White"
CornerRadius="12"
Margin="24"
HorizontalOptions="Center"
VerticalOptions="Center">
<StackLayout Orientation="Horizontal">
<CheckBox x:Name="checkBox"
VerticalOptions="Center" />
<Label Text="Check the CheckBox to modify the Grid background color."
VerticalOptions="Center" />
</StackLayout>
</Frame>
</Grid>
En este ejemplo, la clase Style implícita se destina a objetos Grid. Cuando la propiedad IsChecked
de CheckBox es false
, el color de fondo de Grid se establece en blanco. Cuando la propiedad CheckBox.IsChecked
se convierte en true
, se desencadena un cambio de VisualState, y el color de fondo de Grid cambia a negro:
Desencadenador de estado de dispositivos
DeviceStateTrigger desencadena un cambio de VisualState basado en la plataforma del dispositivo en que se ejecuta la aplicación. Este desencadenador tiene una única propiedad enlazable:
- Device, de tipo
string
, que indica la plataforma del dispositivo en la que debe aplicarse VisualState.
Nota:
El elemento DeviceStateTrigger deriva de la clase StateTriggerBase y, por tanto, puede adjuntar un controlador de eventos al evento IsActiveChanged
.
En el siguiente ejemplo de XAML, se muestra una clase Style que incluye objetos DeviceStateTrigger:
<Style x:Key="DeviceStateTriggerPageStyle"
TargetType="ContentPage">
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup>
<VisualState x:Name="iOS">
<VisualState.StateTriggers>
<DeviceStateTrigger Device="iOS" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Property="BackgroundColor"
Value="Silver" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Android">
<VisualState.StateTriggers>
<DeviceStateTrigger Device="Android" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Property="BackgroundColor"
Value="#2196F3" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
En este ejemplo, la clase Style explícita se destina a objetos ContentPage. Los objetos ContentPage que usan el estilo definen su color de fondo en plateado en iOS, en azul pálido en Android.
Desencadenador de estado de orientación
OrientationStateTrigger desencadena un cambio de VisualState cuando varía la orientación del dispositivo. Este desencadenador tiene una única propiedad enlazable:
- Orientation, de tipo DisplayOrientation, que indica la orientación a la que debe aplicarse VisualState.
Nota:
El elemento OrientationStateTrigger
deriva de la clase StateTriggerBase y, por tanto, puede adjuntar un controlador de eventos al evento IsActiveChanged
.
En el siguiente ejemplo de XAML, se muestra una clase Style que incluye objetos OrientationStateTrigger:
<Style x:Key="OrientationStateTriggerPageStyle"
TargetType="ContentPage">
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup>
<VisualState x:Name="Portrait">
<VisualState.StateTriggers>
<OrientationStateTrigger Orientation="Portrait" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Property="BackgroundColor"
Value="Silver" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Landscape">
<VisualState.StateTriggers>
<OrientationStateTrigger Orientation="Landscape" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Property="BackgroundColor"
Value="White" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
En este ejemplo, la clase Style explícita se destina a objetos ContentPage. Los objetos ContentPage que usan el estilo definen su color de fondo en plateado cuando la orientación es vertical y en blanco cuando la orientación es horizontal.