Xamarin.Forms Gatilhos
Os gatilhos permitem expressar ações declarativamente em XAML que alteram a aparência dos controles com base em eventos ou alterações de propriedade. Além disso, os gatilhos de estado, que são um grupo especializado de gatilhos, definem quando um VisualState
deve ser aplicado.
Você pode atribuir um gatilho diretamente a um controle ou adicioná-lo a um dicionário de recursos na página ou aplicativo a ser aplicado a vários controles.
Disparadores de propriedade
Um gatilho simples pode ser expresso puramente em XAML, adicionando um elemento Trigger
a uma coleção de gatilhos do controle.
Este exemplo mostra um gatilho que altera uma cor da tela de fundo Entry
quando recebe o foco:
<Entry Placeholder="enter name">
<Entry.Triggers>
<Trigger TargetType="Entry"
Property="IsFocused" Value="True">
<Setter Property="BackgroundColor" Value="Yellow" />
<!-- multiple Setters elements are allowed -->
</Trigger>
</Entry.Triggers>
</Entry>
As partes importantes da declaração do gatilho são:
TargetType – o tipo de controle ao qual o gatilho se aplica.
Propriedade – a propriedade no controle que é monitorado.
Valor – o valor, quando ocorre para a propriedade monitorada, que faz com que o gatilho seja ativado.
Setter – uma coleção de elementos
Setter
pode ser adicionada quando a condição do gatilho for atendida. Você deve especificarProperty
eValue
para definir.EnterActions e ExitActions (não mostrado) – são escritos em código e podem ser usados em (ou em vez de) elementos
Setter
. Eles são descritos abaixo.
Aplicar um gatilho usando um estilo
Gatilhos também podem ser adicionados a uma declaração Style
em um controle, em uma página ou um aplicativo ResourceDictionary
. Este exemplo declara um estilo implícito (ou seja, não Key
está definido), o que significa que ele será aplicado a todos os Entry
controles na página.
<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="Entry">
<Style.Triggers>
<Trigger TargetType="Entry"
Property="IsFocused" Value="True">
<Setter Property="BackgroundColor" Value="Yellow" />
<!-- multiple Setters elements are allowed -->
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
</ContentPage.Resources>
Gatilhos de dados
Os gatilhos de dados usam a associação de dados para monitorar outro controle para fazer com que Setter
s sejam chamados. Em vez do atributo Property
em um gatilho de propriedade, defina o atributo Binding
para monitorar o valor especificado.
O exemplo a seguir usa a sintaxe de associação de dados {Binding Source={x:Reference entry}, Path=Text.Length}
que é como nos referimos às propriedades de outro controle. Quando o tamanho do entry
for zero, o gatilho será ativado. Neste exemplo, o gatilho desabilita o botão quando a entrada está vazia.
<!-- the x:Name is referenced below in DataTrigger-->
<!-- tip: make sure to set the Text="" (or some other default) -->
<Entry x:Name="entry"
Text=""
Placeholder="required field" />
<Button x:Name="button" Text="Save"
FontSize="Large"
HorizontalOptions="Center">
<Button.Triggers>
<DataTrigger TargetType="Button"
Binding="{Binding Source={x:Reference entry},
Path=Text.Length}"
Value="0">
<Setter Property="IsEnabled" Value="False" />
<!-- multiple Setters elements are allowed -->
</DataTrigger>
</Button.Triggers>
</Button>
Dica
Ao avaliar Path=Text.Length
sempre, forneça um valor padrão para a propriedade de destino (por exemplo, Text=""
) porque caso contrário, será null
e o gatilho não funcionará como você espera.
Além de Setter
especificar s, você também pode fornecer EnterActions
e ExitActions
.
Gatilhos de evento
O elemento EventTrigger
requer apenas uma propriedade Event
, como "Clicked"
no exemplo a seguir.
<EventTrigger Event="Clicked">
<local:NumericValidationTriggerAction />
</EventTrigger>
Observe que não há elementos Setter
, mas, em vez disso, uma referência a uma classe definida por local:NumericValidationTriggerAction
, que requer que o xmlns:local
seja declarado no XAML da página:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:WorkingWithTriggers;assembly=WorkingWithTriggers"
A classe em si implementa TriggerAction
, o que significa que ela deve fornecer uma substituição para o método Invoke
que é chamado sempre que ocorre o evento de gatilho.
Uma implementação de ação do gatilho deve:
Implementar a classe
TriggerAction<T>
genérica com o parâmetro genérico correspondente com o tipo de controle ao qual o gatilho será aplicado. É possível usar superclasses, comoVisualElement
, para gravar ações de gatilho que funcionam com uma variedade de controles ou especificar um tipo de controle, comoEntry
.Substitua o
Invoke
método – isso é chamado sempre que os critérios de gatilho são atendidos.Outra opção é expor propriedades que podem ser definidas no XAML quando o gatilho é declarado. Para obter um exemplo disso, confira a classe
VisualElementPopTriggerAction
no respectivo aplicativo de exemplo.
public class NumericValidationTriggerAction : TriggerAction<Entry>
{
protected override void Invoke (Entry entry)
{
double result;
bool isValid = Double.TryParse (entry.Text, out result);
entry.TextColor = isValid ? Color.Default : Color.Red;
}
}
O gatilho de evento pode ser consumido do XAML:
<EventTrigger Event="TextChanged">
<local:NumericValidationTriggerAction />
</EventTrigger>
Tenha cuidado ao compartilhar gatilhos em um ResourceDictionary
, pois uma instância será compartilhada entre os controles para que qualquer estado que está configurado uma vez se aplique a todos.
Observe que os gatilhos de evento não dão suporte a EnterActions
e ExitActions
descritos abaixo.
Vários gatilhos
Um MultiTrigger
é semelhante a um Trigger
ou DataTrigger
, exceto que pode haver mais de uma condição. Todas as condições devem ser verdadeiras antes de Setter
s serem disparados.
Aqui está um exemplo de um gatilho para um botão que é associado a duas entradas diferentes (email
e phone
):
<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>
A coleção Conditions
também pode conter elementos PropertyCondition
como este:
<PropertyCondition Property="Text" Value="OK" />
Criar um gatilho múltiplo que “exige tudo”
O gatilho múltiplo apenas atualiza seu controle quando todas as condições são verdadeiras. O teste para "todos os comprimentos de campo são zero" (como uma página de logon em que todas as entradas devem ser concluídas) é complicado porque você deseja uma condição "em que Text.Length > 0", mas isso não pode ser expresso no XAML.
Isso pode ser feito com um IValueConverter
. O código de conversor abaixo transforma o Text.Length
que se associa a um bool
que indica se um campo está vazio ou não:
public class MultiTriggerConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
if ((int)value > 0) // length > 0 ?
return true; // some data has been entered
else
return false; // input is empty
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
throw new NotSupportedException ();
}
}
Para usar esse conversor em um gatilho múltiplo, primeiro adicione-o ao dicionário de recursos da página (junto com uma definição de namespace xmlns:local
personalizada):
<ResourceDictionary>
<local:MultiTriggerConverter x:Key="dataHasBeenEntered" />
</ResourceDictionary>
O XAML é mostrado abaixo. Observe as seguintes diferenças do primeiro exemplo de gatilho múltiplo:
- O botão tem
IsEnabled="false"
definido por padrão. - As condições de vários gatilhos usam o conversor para transformar o
Text.Length
valor em umboolean
. - Quando todas as condições são
true
, o setter faz a propriedadetrue
doIsEnabled
botão .
<Entry x:Name="user" Text="" Placeholder="user name" />
<Entry x:Name="pwd" Text="" Placeholder="password" />
<Button x:Name="loginButton" Text="Login"
FontSize="Large"
HorizontalOptions="Center"
IsEnabled="false">
<Button.Triggers>
<MultiTrigger TargetType="Button">
<MultiTrigger.Conditions>
<BindingCondition Binding="{Binding Source={x:Reference user},
Path=Text.Length,
Converter={StaticResource dataHasBeenEntered}}"
Value="true" />
<BindingCondition Binding="{Binding Source={x:Reference pwd},
Path=Text.Length,
Converter={StaticResource dataHasBeenEntered}}"
Value="true" />
</MultiTrigger.Conditions>
<Setter Property="IsEnabled" Value="True" />
</MultiTrigger>
</Button.Triggers>
</Button>
Essas capturas de tela mostram a diferença entre os dois exemplos de gatilho múltiplo acima. Na parte superior das telas, a entrada de texto em apenas um Entry
é suficiente para habilitar o botão Salvar.
Na parte inferior das telas, o botão Logon permanece inativo até que ambos os campos contenham dados.
EnterActions e ExitActions
Outra maneira de implementar alterações quando ocorre um gatilho é adicionando as coleções EnterActions
e ExitActions
e especificando as implementações TriggerAction<T>
.
A coleção EnterActions
é usada para definir um IList
de TriggerAction
objetos que serão invocados quando a condição do gatilho for atendida. A coleção ExitActions
é usada para definir um IList
de TriggerAction
objetos que serão invocados depois que a condição do gatilho não for mais atendida.
Observação
Os objetos TriggerAction
definidos nas coleções EnterActions
e ExitActions
são ignorados pela classe EventTrigger
.
Você pode fornecer eEnterActions
e ExitActions
também Setter
em um gatilho, mas lembre-se de que os Setter
s são chamados imediatamente (eles não esperam o EnterAction
ou ExitAction
para concluir). Como alternativa, você pode executar tudo no código e não usar Setter
s.
<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>
<!-- You can use both Enter/Exit and Setter together if required -->
</Trigger>
</Entry.Triggers>
</Entry>
Como sempre, quando uma classe é referenciada no XAML você deve declarar um namespace como xmlns:local
, conforme mostrado aqui:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:WorkingWithTriggers;assembly=WorkingWithTriggers"
O código FadeTriggerAction
é mostrado abaixo:
public class FadeTriggerAction : TriggerAction<VisualElement>
{
public int StartsFrom { set; get; }
protected override void Invoke(VisualElement sender)
{
sender.Animate("FadeTriggerAction", new Animation((d) =>
{
var val = StartsFrom == 1 ? d : 1 - d;
// so i was aiming for a different color, but then i liked the pink :)
sender.BackgroundColor = Color.FromRgb(1, val, 1);
}),
length: 1000, // milliseconds
easing: Easing.Linear);
}
}
Gatilhos de estado
Os gatilhos de estado são um grupo especializado de gatilhos que definem as condições sob as quais um VisualState
deve ser aplicado.
Os gatilhos de estado são adicionados à StateTriggers
coleção de um VisualState
. Essa coleção pode conter um único gatilho de estado ou vários gatilhos de estado. Um VisualState
será aplicado quando qualquer gatilho de estado na coleção estiver ativo.
Ao usar gatilhos de estado para controlar estados visuais, Xamarin.Forms usa as seguintes regras de precedência para determinar qual gatilho (e correspondente VisualState
) estará ativo:
- Qualquer gatilho que deriva de
StateTriggerBase
. - Um
AdaptiveTrigger
ativado devido àMinWindowWidth
condição que está sendo atendida. - Um
AdaptiveTrigger
ativado devido àMinWindowHeight
condição que está sendo atendida.
Se vários gatilhos estiverem ativos simultaneamente (por exemplo, dois gatilhos personalizados), o primeiro gatilho declarado na marcação terá precedência.
Observação
Os gatilhos de estado podem ser definidos em um Style
ou diretamente em elementos.
Para obter mais informações sobre estados visuais, consulte Xamarin.Forms Visual State Manager.
Gatilho de estado
A StateTrigger
classe , que deriva da StateTriggerBase
classe , tem uma IsActive
propriedade associável. Um StateTrigger
dispara uma VisualState
alteração quando a propriedade altera o IsActive
valor.
A StateTriggerBase
classe , que é a classe base para todos os gatilhos de estado, tem uma IsActive
propriedade e um IsActiveChanged
evento. Esse evento é acionado sempre que ocorre uma VisualState
alteração. Além disso, a StateTriggerBase
classe tem métodos e OnDetached
substituíveisOnAttached
.
Importante
A StateTrigger.IsActive
propriedade associável oculta a propriedade herdada StateTriggerBase.IsActive
.
O exemplo XAML a seguir mostra um Style
que inclui StateTrigger
objetos:
<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>
Neste exemplo, os objetos de destino Grid
implícitosStyle
. Quando a IsToggled
propriedade do objeto associado é true
, a cor da tela de fundo do Grid
é definida como preta. Quando a IsToggled
propriedade do objeto associado se torna false
, uma VisualState
alteração é disparada e a cor da tela de fundo do Grid
torna-se branca.
Além disso, sempre que ocorre uma VisualState
alteração, o IsActiveChanged
evento para o VisualState
é acionado. Cada VisualState
um registra um manipulador 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}");
}
Neste exemplo, quando um manipulador para o IsActiveChanged
evento é acionado, o manipulador gera se o VisualState
está ativo ou não. Por exemplo, as seguintes mensagens são enviadas para a janela do console ao alterar do Checked
estado visual para o Unchecked
estado visual:
Checked state active: False
Unchecked state active: True
Observação
Gatilhos de estado personalizados podem ser criados derivando da StateTriggerBase
classe e substituindo os métodos e OnDetached
para executar todos os OnAttached
registros e limpeza necessários.
Gatilho adaptável
Um AdaptiveTrigger
dispara uma VisualState
alteração quando a janela é uma altura ou largura especificada. Esse gatilho tem duas propriedades associáveis:
MinWindowHeight
, do tipodouble
, que indica a altura mínima da janela na qual oVisualState
deve ser aplicado.MinWindowWidth
, do tipodouble
, que indica a largura mínima da janela na qual oVisualState
deve ser aplicado.
Observação
O AdaptiveTrigger
deriva da StateTriggerBase
classe e, portanto, pode anexar um manipulador de eventos ao IsActiveChanged
evento.
O exemplo XAML a seguir mostra um Style
que inclui AdaptiveTrigger
objetos :
<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>
Neste exemplo, os objetos de destino StackLayout
implícitosStyle
. Quando a largura da janela estiver entre 0 e 800 unidades independentes do dispositivo, StackLayout
os objetos aos quais o Style
é aplicado terão uma orientação vertical. Quando a largura da janela é >= 800 unidades independentes do dispositivo, a VisualState
alteração é disparada e a StackLayout
orientação muda para horizontal:
Exemplo de de Exemplo de
As MinWindowHeight
propriedades e MinWindowWidth
podem ser usadas de forma independente ou em conjunto umas com as outras. O XAML a seguir mostra um exemplo de configuração de ambas as propriedades:
<AdaptiveTrigger MinWindowWidth="800"
MinWindowHeight="1200"/>
Neste exemplo, o AdaptiveTrigger
indica que o correspondente VisualState
será aplicado quando a largura da janela atual for >= 800 unidades independentes do dispositivo e a altura da janela atual for >= 1200 unidades independentes do dispositivo.
Comparar gatilho de estado
O CompareStateTrigger
dispara uma VisualState
alteração quando uma propriedade é igual a um valor específico. Esse gatilho tem duas propriedades associáveis:
Property
, do tipoobject
, que indica a propriedade que está sendo comparada pelo gatilho.Value
, do tipoobject
, que indica o valor no qual oVisualState
deve ser aplicado.
Observação
O CompareStateTrigger
deriva da StateTriggerBase
classe e, portanto, pode anexar um manipulador de eventos ao IsActiveChanged
evento.
O exemplo XAML a seguir mostra um Style
que inclui CompareStateTrigger
objetos :
<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>
Neste exemplo, os objetos de destino Grid
implícitosStyle
. Quando a IsChecked
propriedade do CheckBox
é false
, a cor da tela de fundo do Grid
é definida como branca. Quando a CheckBox.IsChecked
propriedade se torna true
, uma VisualState
alteração é disparada e a cor da tela de fundo do Grid
se torna preta:
Gatilho de estado do dispositivo
O DeviceStateTrigger
dispara uma VisualState
alteração com base na plataforma do dispositivo em que o aplicativo está sendo executado. Esse gatilho tem uma única propriedade associável:
Device
, do tipostring
, que indica a plataforma do dispositivo na qual oVisualState
deve ser aplicado.
Observação
O DeviceStateTrigger
deriva da StateTriggerBase
classe e, portanto, pode anexar um manipulador de eventos ao IsActiveChanged
evento.
O exemplo XAML a seguir mostra um Style
que inclui DeviceStateTrigger
objetos :
<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>
<VisualState x:Name="UWP">
<VisualState.StateTriggers>
<DeviceStateTrigger Device="UWP" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Property="BackgroundColor"
Value="Aquamarine" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
Neste exemplo, os objetos de destino ContentPage
explícitosStyle
. ContentPage
os objetos que consomem o estilo definem sua cor da tela de fundo como prata no iOS, para azul claro no Android e para aquamarine na UWP. As capturas de tela a seguir mostram as páginas resultantes no iOS e no Android:
Gatilho de estado de orientação
O OrientationStateTrigger
dispara uma VisualState
alteração quando a orientação do dispositivo é alterada. Esse gatilho tem uma única propriedade associável:
Orientation
, do tipoDeviceOrientation
, que indica a orientação à qual oVisualState
deve ser aplicado.
Observação
O OrientationStateTrigger
deriva da StateTriggerBase
classe e, portanto, pode anexar um manipulador de eventos ao IsActiveChanged
evento.
O exemplo XAML a seguir mostra um Style
que inclui OrientationStateTrigger
objetos :
<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>
Neste exemplo, os objetos de destino ContentPage
explícitosStyle
. ContentPage
os objetos que consomem o estilo definem a cor da tela de fundo como prata quando a orientação é retrato e definem a cor da tela de fundo como branca quando a orientação é paisagem.