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 se deve aplicar VisualState.

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.

Gatilhos de propriedades

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 ele ocorre para a propriedade monitorada, que faz o gatilho ativar.

  • Setter – uma coleção de elementos Setter pode ser adicionada quando a condição do gatilho for atendida. Você deve especificar Property e Value 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.

Aplicação de 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 (por exemplo, nenhum Key está definido), o que significa que ele se aplicará a todos os controles Entry 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 Setters 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 especificar Setters, 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, como VisualElement, para gravar ações de gatilho que funcionam com uma variedade de controles ou especificar um tipo de controle, como Entry.

  • Substituir o método Invoke – isso é chamado sempre que os critérios do gatilho forem 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 nem a ExitActionsdescrito abaixo.

Múltiplos 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 Setters 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. Testar "todos os comprimentos de campo são zero" (como uma página de logon onde todas as entradas devem ser concluídas) é complicado porque você deseja uma condição "onde Text.Length > 0", mas isso não pode ser expresso em 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 gatilho múltiplo usam o conversor para transformar o valor Text.Length em um boolean.
  • Quando todas as condições forem true, o setter transformará o IsEnabled do botão na propriedade true.
<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.

Exemplos de MultiTrigger

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 ambosEnterActions e ExitActions, bem como Setters em um gatilho, mas lembre-se de que Setters são chamados imediatamente (eles não aguardam o EnterAction ou o ExitAction ser concluído). Como alternativa, você pode executar tudo no código e não usar Setters.

<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 à coleção de StateTriggers de um VisualState. Essa coleção pode conter um 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 use as seguintes regras de precedência para determinar qual gatilho (e VisualStatecorrespondente) estará ativo:

  1. Um gatilho que deriva de StateTriggerBase.
  2. Um AdaptiveTrigger ativado porque a condição MinWindowWidth foi atendida.
  3. Um AdaptiveTrigger ativado porque a condição MinWindowHeight foi atendida.

Se múltiplos gatinhos estiverem simultaneamente ativos (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 Style ou diretamente nos elementos.

Para obter mais informações sobre estados visuais, consulte Xamarin.Forms Visual State Manager.

Gatilho de estado

A classe StateTrigger, que deriva da classe StateTriggerBase, tem uma propriedade associável IsActive. Um StateTrigger aciona o gatilho de uma alteração VisualState quando a propriedade IsActive muda de valor.

A classe StateTriggerBase, que é a classe base de todos os gatilhos de estado, tem uma propriedade IsActive e um evento IsActiveChanged. Esse evento é disparado sempre que ocorre uma alteração em VisualState. Além disso, a StateTriggerBase classe tem métodos e substituíveis OnDetachedOnAttached.

Importante

A propriedade associável StateTrigger.IsActive oculta a propriedade herdada StateTriggerBase.IsActive.

O exemplo de XAML a seguir mostra um Style que inclui os 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>

Nesse exemplo, o Style implícito tem como destino os objetos Grid. Quando a propriedade IsToggled do objeto associado é true, a cor da tela de fundo de Grid é definida como preto. Quando a propriedade IsToggled do objeto associado se torna false, uma alteração de VisualState é disparada, e a cor da tela de fundo de Grid se torna branca.

Além disso, a cada vez que a alteração VisualState ocorre, o evento IsActiveChanged de VisualState é disparado. Cada VisualState registra um manipulador de eventos para esse 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}");
}

Nesse exemplo, quando um manipulador do evento IsActiveChanged é disparado, o manipulador informa se VisualState está ativo ou não. Por exemplo, as mensagens a seguir são enviadas para a janela do console ao alterar do estado visual Checked para o estado visual Unchecked:

Checked state active: False
Unchecked state active: True

Observação

Os gatilhos de estado personalizados podem ser criados derivando da StateTriggerBase classe e substituindo os OnAttached métodos e OnDetached para executar quaisquer registros e limpeza necessários.

Gatilho adaptável

Um AdaptiveTrigger dispara uma alteração VisualState quando a janela tem a altura ou largura especificada. Esse gatilho tem duas propriedades associáveis:

Observação

AdaptiveTrigger deriva da classe StateTriggerBase e, portanto, pode anexar um manipulador de eventos ao evento IsActiveChanged.

O exemplo de XAML a seguir mostra um Style que inclui os 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>

Nesse exemplo, o Style implícito tem como destino os objetos StackLayout. Quando a largura da janela está entre 0 e 800 unidades independentes de dispositivo, os objetos de StackLayout aos quais Style é aplicado terão uma orientação vertical. Quando a largura da janela é >= 800 unidades independentes de dispositivo, a alteração é acionada VisualState e a StackLayout orientação muda para horizontal:

Vertical StackLayout VisualStateHorizontal: StackLayout, VisualState

As propriedades MinWindowHeight e MinWindowWidth podem ser usadas de forma independente ou em conjunto uma com a outra. O XAML a seguir mostra um exemplo da definição das duas 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 de dispositivo e a altura da janela atual for >= 1200 unidades independentes de dispositivo.

Comparar gatilho de estado

O CompareStateTrigger dispara uma alteração de VisualState quando a propriedade é igual a um valor específico. Esse gatilho tem duas propriedades associáveis:

  • Property, do tipo object, que indica a propriedade comparada pelo gatilho.
  • Value, do tipo object, que indica o valor no qual VisualState deve ser aplicado.

Observação

CompareStateTrigger deriva da classe StateTriggerBase e, portanto, pode anexar um manipulador de eventos ao evento IsActiveChanged.

O exemplo de XAML a seguir mostra um Style que inclui os 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>

Nesse exemplo, o Style implícito tem como destino os objetos Grid. Quando a propriedade IsChecked do objeto CheckBox é false, a cor da tela de fundo de Grid é definida como branca. Quando a propriedade CheckBox.IsChecked se torna true, uma alteração de VisualState é disparada, e a cor da tela de fundo de Grid se torna preta:

Captura de tela de uma alteração de estado visual acionada, no iOS e Android, com gatilho desmarcado.Captura de tela de uma alteração de estado visual acionada, no iOS e Android, com gatilho marcado.

Gatilho de estado de dispositivo

O DeviceStateTrigger dispara uma alteração de VisualState com base na plataforma do dispositivo na qual o aplicativo está em execução. Esse gatilho tem uma única propriedade associável:

  • Device, do tipo string, que indica a plataforma do dispositivo na qual VisualState deve ser aplicado.

Observação

DeviceStateTrigger deriva da classe StateTriggerBase e, portanto, pode anexar um manipulador de eventos ao evento IsActiveChanged.

O exemplo de XAML a seguir mostra um Style que inclui os 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>
                <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>

Nesse exemplo, o Style explícito tem como destino os objetos ContentPage. Os objetos ContentPage que consomem o estilo definem a cor de plano de fundo como prata no iOS, azul claro no Android e água-marinha no UWP. As capturas de tela a seguir mostram as páginas resultantes no iOS e Android:

Captura de tela de uma alteração de estado visual disparada, no iOS e no Android

Gatilho de estado de orientação

O OrientationStateTrigger dispara uma alteração VisualState quando a orientação do dispositivo é alterada. Esse gatilho tem uma única propriedade associável:

Observação

OrientationStateTrigger deriva da classe StateTriggerBase e, portanto, pode anexar um manipulador de eventos ao evento IsActiveChanged.

O exemplo de XAML a seguir mostra um Style que inclui os 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>

Nesse exemplo, o Style explícito tem como destino os objetos ContentPage. Os objetos ContentPage que consomem o estilo definem sua cor de plano de fundo como prata quando a orientação é retrato e como branco quando a orientação é paisagem.