O Gerenciador de estado visual do Xamarin. FormsThe Xamarin.Forms Visual State Manager

Baixar Exemplo Baixar o exemploDownload Sample Download the sample

Use o Gerenciador de estado visual para fazer alterações em elementos XAML com base em estados visuais definidos a partir do código.Use the Visual State Manager to make changes to XAML elements based on visual states set from code.

O VSM (Visual State Manager) é novo no Xamarin. Forms 3,0.The Visual State Manager (VSM) is new in Xamarin.Forms 3.0. O VSM fornece uma maneira estruturada de fazer alterações visuais na interface do usuário a partir do código.The VSM provides a structured way to make visual changes to the user interface from code. Na maioria dos casos, a interface do usuário do aplicativo é definida em XAML, e esse XAML inclui marcação que descreve como o Gerenciador de estado visual afeta os elementos visuais da interface do usuário.In most cases, the user interface of the application is defined in XAML, and this XAML includes markup describing how the Visual State Manager affects the visuals of the user interface.

O VSM apresenta o conceito de Estados visuais.The VSM introduces the concept of visual states. Uma exibição do Xamarin. Forms, como uma Button pode ter várias aparências visuais diferentes dependendo de seu estado subjacente — se ela está desabilitada ou pressionada ou se tem foco de entrada.A Xamarin.Forms view such as a Button can have several different visual appearances depending on its underlying state — whether it's disabled, or pressed, or has input focus. Esses são os Estados do botão.These are the button's states.

Os Estados visuais são coletados em grupos de Estados visuais.Visual states are collected in visual state groups. Todos os Estados visuais dentro de um grupo de estado visual são mutuamente exclusivos.All the visual states within a visual state group are mutually exclusive. Os Estados visuais e os grupos de Estados visuais são identificados por cadeias de caracteres de texto simples.Both visual states and visual state groups are identified by simple text strings.

O Gerenciador de estado visual do Xamarin. Forms define um grupo de estado visual chamado "CommonStates" com três estados visuais:The Xamarin.Forms Visual State Manager defines one visual state group named "CommonStates" with three visual states:

  • "Normal""Normal"
  • Desabilitado"Disabled"
  • Foco"Focused"

Esse grupo de estado visual tem suporte para todas as classes que derivam de VisualElement, que é a classe base para View e Page.This visual state group is supported for all classes that derive from VisualElement, which is the base class for View and Page.

Você também pode definir seus próprios grupos de estado visual e Estados visuais, como este artigo demonstrará.You can also define your own visual state groups and visual states, as this article will demonstrate.

Observação

Os desenvolvedores do Xamarin. Forms familiarizados com gatilhos estão cientes de que os gatilhos também podem fazer alterações em visuais na interface do usuário com base nas alterações nas propriedades de uma exibição ou no acionamento de eventos.Xamarin.Forms developers familiar with triggers are aware that triggers can also make changes to visuals in the user interface based on changes in a view's properties or the firing of events. No entanto, o uso de gatilhos para lidar com várias combinações dessas alterações pode se tornar bastante confuso.However, using triggers to deal with various combinations of these changes can become quite confusing. Historicamente, o Visual State Manager foi introduzido em ambientes baseados em XAML do Windows para aliviar a confusão resultante de combinações de Estados visuais.Historically, the Visual State Manager was introduced in Windows XAML-based environments to alleviate the confusion resulting from combinations of visual states. Com o VSM, os Estados visuais dentro de um grupo de estado visual são sempre mutuamente exclusivos.With the VSM, the visual states within a visual state group are always mutually exclusive. A qualquer momento, apenas um estado em cada grupo é o estado atual.At any time, only one state in each group is the current state.

Os Estados comunsThe common states

O Gerenciador de estado visual permite que você inclua seções no arquivo XAML que podem alterar a aparência visual de uma exibição se a exibição for normal ou desabilitada ou tiver o foco de entrada.The Visual State Manager allows you to include sections in your XAML file that can change the visual appearance of a view if the view is normal, or disabled, or has the input focus. Eles são conhecidos como Estados comuns.These are known as the common states.

Por exemplo, suponha que você tenha uma exibição Entry em sua página e queira que a aparência visual da Entry seja alterada das seguintes maneiras:For example, suppose you have an Entry view on your page, and you want the visual appearance of the Entry to change in the following ways:

  • O Entry deve ter um plano de fundo rosa quando o Entry estiver desabilitado.The Entry should have a pink background when the Entry is disabled.
  • O Entry deve ter um plano de fundo de verde-limão normalmente.The Entry should have a lime background normally.
  • A Entry deve expandir para duas vezes sua altura normal quando ela tem o foco de entrada.The Entry should expand to twice its normal height when it has input focus.

Você pode anexar a marcação VSM a uma exibição individual ou pode defini-la em um estilo se ela se aplicar a várias exibições.You can attach the VSM markup to an individual view, or you can define it in a style if it applies to multiple views. As próximas duas seções descrevem essas abordagens.The next two sections describe these approaches.

Marcação VSM em uma exibiçãoVSM markup on a view

Para anexar a marcação VSM a uma exibição Entry, primeiro separe as Entry nas marcas inicial e final:To attach VSM markup to an Entry view, first separate the Entry into start and end tags:

<Entry FontSize="18">

</Entry>

Ele recebe um tamanho de fonte explícito, pois um dos Estados usará a propriedade FontSize para dobrar o tamanho do texto na Entry.It's given an explicit font size because one of the states will use the FontSize property to double the size of the text in the Entry.

Em seguida, insira VisualStateManager.VisualStateGroups marcas entre essas marcas:Next, insert VisualStateManager.VisualStateGroups tags between those tags:

<Entry FontSize="18">
    <VisualStateManager.VisualStateGroups>

    </VisualStateManager.VisualStateGroups>
</Entry>

VisualStateGroups é uma propriedade vinculável associada definida pela classe VisualStateManager .VisualStateGroups is an attached bindable property defined by the VisualStateManager class. (Para obter mais informações sobre as propriedades vinculáveis anexadas, consulte o artigo Propriedades anexadas.) É assim que a propriedade VisualStateGroups é anexada ao objeto Entry.(For more information on attached bindable properties, see the article Attached properties.) This is how the VisualStateGroups property is attached to the Entry object.

A propriedade VisualStateGroups é do tipo VisualStateGroupList, que é uma coleção de objetos VisualStateGroup .The VisualStateGroups property is of type VisualStateGroupList, which is a collection of VisualStateGroup objects. Dentro das marcas de VisualStateManager.VisualStateGroups, insira um par de marcas de VisualStateGroup para cada grupo de Estados visuais que você deseja incluir:Within the VisualStateManager.VisualStateGroups tags, insert a pair of VisualStateGroup tags for each group of visual states you wish to include:

<Entry FontSize="18">
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="CommonStates">

        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
</Entry>

Observe que a marca VisualStateGroup tem um atributo x:Name indicando o nome do grupo.Notice that the VisualStateGroup tag has an x:Name attribute indicating the name of the group. A classe VisualStateGroup define uma propriedade Name que você pode usar em vez disso:The VisualStateGroup class defines a Name property that you can use instead:

<VisualStateGroup Name="CommonStates">

Você pode usar o x:Name ou Name mas não ambos no mesmo elemento.You can use either x:Name or Name but not both in the same element.

A classe VisualStateGroup define uma propriedade chamada States, que é uma coleção de objetos VisualState .The VisualStateGroup class defines a property named States, which is a collection of VisualState objects. States é a Propriedade Content de VisualStateGroups para que você possa incluir as marcas de VisualState diretamente entre as marcas de VisualStateGroup.States is the content property of VisualStateGroups so you can include the VisualState tags directly between the VisualStateGroup tags. (As propriedades de conteúdo são discutidas no artigo sintaxe XAML essencial.)(Content properties are discussed in the article Essential XAML Syntax.)

A próxima etapa é incluir um par de marcas para cada estado visual nesse grupo.The next step is to include a pair of tags for every visual state in that group. Elas também podem ser identificadas usando x:Name ou Name:These also can be identified using x:Name or Name:

<Entry FontSize="18">
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="CommonStates">
            <VisualState x:Name="Normal">

            </VisualState>

            <VisualState x:Name="Focused">

            </VisualState>

            <VisualState x:Name="Disabled">

            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
</Entry>

VisualState define uma propriedade chamada Setters, que é uma coleção de objetos Setter .VisualState defines a property named Setters, which is a collection of Setter objects. Esses são os mesmos objetos Setter que você usa em um objeto Style .These are the same Setter objects that you use in a Style object.

Setters não é a propriedade content de VisualState, portanto, é necessário incluir marcas de elemento de propriedade para a propriedade Setters:Setters is not the content property of VisualState, so it is necessary to include property element tags for the Setters property:

<Entry FontSize="18">
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="CommonStates">
            <VisualState x:Name="Normal">
                <VisualState.Setters>

                </VisualState.Setters>
            </VisualState>

            <VisualState x:Name="Focused">
                <VisualState.Setters>
    
                </VisualState.Setters>
            </VisualState>

            <VisualState x:Name="Disabled">
                <VisualState.Setters>

                </VisualState.Setters>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
</Entry>

Agora você pode inserir um ou mais objetos Setter entre cada par de marcas Setters.You can now insert one or more Setter objects between each pair of Setters tags. Estes são os objetos Setter que definem os Estados visuais descritos anteriormente:These are the Setter objects that define the visual states described earlier:

<Entry FontSize="18">
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="CommonStates">
            <VisualState x:Name="Normal">
                <VisualState.Setters>
                    <Setter Property="BackgroundColor" Value="Lime" />
                </VisualState.Setters>
            </VisualState>

            <VisualState x:Name="Focused">
                <VisualState.Setters>
                    <Setter Property="FontSize" Value="36" />
                </VisualState.Setters>
            </VisualState>

            <VisualState x:Name="Disabled">
                <VisualState.Setters>
                    <Setter Property="BackgroundColor" Value="Pink" />
                </VisualState.Setters>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
</Entry>

Cada marca de Setter indica o valor de uma propriedade específica quando esse estado é atual.Each Setter tag indicates the value of a particular property when that state is current. Qualquer propriedade referenciada por um objeto Setter deve ser apoiada por uma propriedade vinculável.Any property referenced by a Setter object must be backed by a bindable property.

A marcação semelhante a esta é a base da página VSM na exibição no programa de exemplo VsmDemos .Markup similar to this is the basis of the VSM on View page in the VsmDemos sample program. A página inclui três exibições de Entry, mas apenas a segunda tem a marcação VSM anexada a ela:The page includes three Entry views, but only the second one has the VSM markup attached to it:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:VsmDemos"
             x:Class="VsmDemos.MainPage"
             Title="VSM Demos">

    <StackLayout>
        <StackLayout.Resources>
            <Style TargetType="Entry">
                <Setter Property="Margin" Value="20, 0" />
                <Setter Property="FontSize" Value="18" />
            </Style>

            <Style TargetType="Label">
                <Setter Property="Margin" Value="20, 30, 20, 0" />
                <Setter Property="FontSize" Value="Large" />
            </Style>
        </StackLayout.Resources>

        <Label Text="Normal Entry:" />

        <Entry />

        <Label Text="Entry with VSM: " />

        <Entry>
            <VisualStateManager.VisualStateGroups>
                <VisualStateGroup x:Name="CommonStates">
                    
                    <VisualState x:Name="Normal">
                        <VisualState.Setters>
                            <Setter Property="BackgroundColor" Value="Lime" />
                        </VisualState.Setters>
                    </VisualState>

                    <VisualState x:Name="Focused">
                        <VisualState.Setters>
                            <Setter Property="FontSize" Value="36" />
                        </VisualState.Setters>
                    </VisualState>

                    <VisualState x:Name="Disabled">
                        <VisualState.Setters>
                            <Setter Property="BackgroundColor" Value="Pink" />
                        </VisualState.Setters>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>

            <Entry.Triggers>
                <DataTrigger TargetType="Entry"
                             Binding="{Binding Source={x:Reference entry3},
                                               Path=Text.Length}"
                             Value="0">
                    <Setter Property="IsEnabled" Value="False" />
                </DataTrigger>
            </Entry.Triggers>
        </Entry>

        <Label Text="Entry to enable 2nd Entry:" />

        <Entry x:Name="entry3"
               Text=""
               Placeholder="Type something to enable 2nd Entry" />
    </StackLayout>
</ContentPage>

Observe que a segunda Entry também tem uma DataTrigger como parte de sua coleção de Trigger.Notice that the second Entry also has a DataTrigger as part of its Trigger collection. Isso faz com que o Entry seja desabilitado até que algo seja digitado na terceira Entry.This causes the Entry to be disabled until something is typed into the third Entry. Aqui está a página na inicialização em execução no iOS, no Android e no Plataforma Universal do Windows (UWP):Here's the page at startup running on iOS, Android, and the Universal Windows Platform (UWP):

VSM na exibição: desabilitadoVSM on View: Disabled

O estado do visual atual é "desabilitado" para que o plano de fundo da segunda Entry seja rosa nas telas do iOS e do Android.The current visual state is "Disabled" so the background of the second Entry is pink on the iOS and Android screens. A implementação do UWP de Entry não permite definir a cor do plano de fundo quando o Entry está desabilitado.The UWP implementation of Entry does not allow setting the background color when the Entry is disabled.

Quando você insere um texto na terceira Entry, a segunda Entry muda para o estado "normal" e o plano de fundo agora é verde-limão:When you enter some text into the third Entry, the second Entry switches into the "Normal" state, and the background is now lime:

VSM na exibição: normalVSM on View: Normal

Quando você toca na segunda Entry, ele obtém o foco de entrada.When you touch the second Entry, it gets the input focus. Ele alterna para o estado "focado" e expande para duas vezes sua altura:It switches to the "Focused" state and expands to twice its height:

VSM na exibição: focadoVSM on View: Focused

Observe que o Entry não retém o plano de fundo de verde-limão quando Obtém o foco de entrada.Notice that the Entry does not retain the lime background when it gets the input focus. Como o Gerenciador de estado visual alterna entre os Estados visuais, as propriedades definidas pelo estado anterior são desdefinidas.As the Visual State Manager switches between the visual states, the properties set by the previous state are unset. Tenha em mente que os Estados visuais são mutuamente exclusivos.Keep in mind that the visual states are mutually exclusive. O estado "normal" não significa apenas que o Entry está habilitado.The "Normal" state does not mean solely that the Entry is enabled. Isso significa que a Entry está habilitada e não tem foco de entrada.It means that the Entry is enabled and does not have input focus.

Se você quiser que o Entry tenha um plano de fundo de verde-limão no estado "focado", adicione outra Setter a esse estado visual:If you want the Entry to have a lime background in the "Focused" state, add another Setter to that visual state:

<VisualState x:Name="Focused">
    <VisualState.Setters>
        <Setter Property="FontSize" Value="36" />
        <Setter Property="BackgroundColor" Value="Lime" />
    </VisualState.Setters>
</VisualState>

Para que esses Setter objetos funcionem corretamente, um VisualStateGroup deve conter VisualState objetos para todos os Estados nesse grupo.In order for these Setter objects to work properly, a VisualStateGroup must contain VisualState objects for all the states in that group. Se houver um estado visual que não tenha nenhum objeto de Setter, inclua assim mesmo como uma marca vazia:If there is a visual state that does not have any Setter objects, include it anyway as an empty tag:

<VisualState x:Name="Normal" />

Marcação do Gerenciador de estado visual em um estiloVisual State Manager markup in a style

Geralmente, é necessário compartilhar a mesma marcação do Gerenciador de estado visual entre duas ou mais exibições.It's often necessary to share the same Visual State Manager markup among two or more views. Nesse caso, você desejará colocar a marcação em uma definição de Style.In this case, you'll want to put the markup in a Style definition.

Aqui está o Style implícito existente para os elementos Entry na página VSM na exibição :Here's the existing implicit Style for the Entry elements in the VSM On View page:

<Style TargetType="Entry">
    <Setter Property="Margin" Value="20, 0" />
    <Setter Property="FontSize" Value="18" />
</Style> 

Adicione marcas de Setter para a propriedade vinculável VisualStateManager.VisualStateGroups anexada:Add Setter tags for the VisualStateManager.VisualStateGroups attached bindable property:

<Style TargetType="Entry">
    <Setter Property="Margin" Value="20, 0" />
    <Setter Property="FontSize" Value="18" />
    <Setter Property="VisualStateManager.VisualStateGroups">

    </Setter>
</Style> 

A propriedade de conteúdo para Setter é Value, portanto, o valor da propriedade Value pode ser especificado diretamente dentro dessas marcas.The content property for Setter is Value, so the value of the Value property can be specified directly within those tags. Essa propriedade é do tipo VisualStateGroupList:That property is of type VisualStateGroupList:

<Style TargetType="Entry">
    <Setter Property="Margin" Value="20, 0" />
    <Setter Property="FontSize" Value="18" />
    <Setter Property="VisualStateManager.VisualStateGroups">
        <VisualStateGroupList>

        </VisualStateGroupList>
    </Setter>
</Style> 

Dentro dessas marcas, você pode incluir um ou mais objetos VisualStateGroup:Within those tags you can include one of more VisualStateGroup objects:

<Style TargetType="Entry">
    <Setter Property="Margin" Value="20, 0" />
    <Setter Property="FontSize" Value="18" />
    <Setter Property="VisualStateManager.VisualStateGroups">
        <VisualStateGroupList>
            <VisualStateGroup x:Name="CommonStates">

            </VisualStateGroup>
        </VisualStateGroupList>
    </Setter>
</Style> 

O restante da marcação VSM é o mesmo que antes.The remainder of the VSM markup is the same as before.

Aqui está o VSM na página de estilo mostrando a marcação VSM completa:Here's the VSM in Style page showing the complete VSM markup:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="VsmDemos.VsmInStylePage"
             Title="VSM in Style">
    <StackLayout>
        <StackLayout.Resources>
            <Style TargetType="Entry">
                <Setter Property="Margin" Value="20, 0" />
                <Setter Property="FontSize" Value="18" />
                <Setter Property="VisualStateManager.VisualStateGroups">
                    <VisualStateGroupList>
                        <VisualStateGroup x:Name="CommonStates">

                            <VisualState x:Name="Normal">
                                <VisualState.Setters>
                                    <Setter Property="BackgroundColor" Value="Lime" />
                                </VisualState.Setters>
                            </VisualState>

                            <VisualState x:Name="Focused">
                                <VisualState.Setters>
                                    <Setter Property="FontSize" Value="36" />
                                    <Setter Property="BackgroundColor" Value="Lime" />
                                </VisualState.Setters>
                            </VisualState>

                            <VisualState x:Name="Disabled">
                                <VisualState.Setters>
                                    <Setter Property="BackgroundColor" Value="Pink" />
                                </VisualState.Setters>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateGroupList>
                </Setter>
            </Style>

            <Style TargetType="Label">
                <Setter Property="Margin" Value="20, 30, 20, 0" />
                <Setter Property="FontSize" Value="Large" />
            </Style>
        </StackLayout.Resources>

        <Label Text="Normal Entry:" />

        <Entry />
        
        <Label Text="Entry with VSM: " />

        <Entry>
            <Entry.Triggers>
                <DataTrigger TargetType="Entry"
                             Binding="{Binding Source={x:Reference entry3},
                                               Path=Text.Length}"
                             Value="0">
                    <Setter Property="IsEnabled" Value="False" />
                </DataTrigger>
            </Entry.Triggers>
        </Entry>

        <Label Text="Entry to enable 2nd Entry:" />

        <Entry x:Name="entry3"
               Text=""
               Placeholder="Type something to enable 2nd Entry" />
    </StackLayout>
</ContentPage>

Agora, todos os Entry modos de exibição nesta página respondem da mesma forma aos seus Estados visuais.Now all the Entry views on this page respond the same way to their visual states. Observe também que o estado "focado" agora inclui um segundo Setter que fornece a cada Entry uma experiência de fundo de verde-limão também quando tem foco de entrada:Notice also that the "Focused" state now includes a second Setter that gives each Entry a lime background also when it has input focus:

VSM em estiloVSM in Style

Definindo seus próprios Estados visuaisDefining your own visual states

Todas as classes que derivam de VisualElement dão suporte aos três Estados comuns "normal", "com foco" e "desabilitado".Every class that derives from VisualElement supports the three common states "Normal", "Focused", and "Disabled". Internamente, a classe VisualElement detecta quando está se tornando habilitada ou desabilitada, ou focada ou desfocada, e chama o método estático de VisualStateManager.GoToState :Internally, the VisualElement class detects when it's becoming enabled or disabled, or focused or unfocused, and calls the static VisualStateManager.GoToState method:

VisualStateManager.GoToState(this, "Focused");

Esse é o único código do Gerenciador de estado visual que você encontrará na classe VisualElement.This is the only Visual State Manager code that you'll find in the VisualElement class. Como GoToState é chamado para cada objeto com base em todas as classes que derivam de VisualElement, você pode usar o Gerenciador de estado visual com qualquer objeto VisualElement para responder a essas alterações.Because GoToState is called for every object based on every class that derives from VisualElement, you can use the Visual State Manager with any VisualElement object to respond to these changes.

Curiosamente, o nome do grupo de estado visual "CommonStates" não é explicitamente referenciado em VisualElement.Interestingly, the name of the visual state group "CommonStates" is not explicitly referenced in VisualElement. O nome do grupo não faz parte da API para o Gerenciador de estado visual.The group name is not part of the API for the Visual State Manager. Em um dos dois programas de exemplo mostrados até agora, você pode alterar o nome do grupo de "CommonStates" para qualquer outra coisa e o programa continuará funcionando.Within one of the two sample program shown so far, you can change the name of the group from "CommonStates" to anything else, and the program will still work. O nome do grupo é meramente uma descrição geral dos Estados nesse grupo.The group name is merely a general description of the states in that group. Ele é compreendido implicitamente que os Estados visuais em qualquer grupo são mutuamente exclusivos: um estado e apenas um estado é atual a qualquer momento.It is implicitly understood that the visual states in any group are mutually exclusive: One state and only one state is current at any time.

Se você quiser implementar seus próprios Estados visuais, precisará chamar VisualStateManager.GoToState do código.If you want to implement your own visual states, you'll need to call VisualStateManager.GoToState from code. Geralmente, você fará essa chamada a partir do arquivo code-behind da sua classe Page.Most often you'll make this call from the code-behind file of your page class.

A página validação do VSM no exemplo de VsmDemos mostra como usar o Gerenciador de estado visual em conexão com a validação de entrada.The VSM Validation page in the VsmDemos sample shows how to use the Visual State Manager in connection with input validation. O arquivo XAML consiste em dois elementos Label, um Entry e Button:The XAML file consists of two Label elements, an Entry, and Button:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="VsmDemos.VsmValidationPage"
             Title="VSM Validation">
    <StackLayout Padding="10, 10">
        
        <Label Text="Enter a U.S. phone number:"
               FontSize="Large" />

        <Entry Placeholder="555-555-5555"
               FontSize="Large"
               Margin="30, 0, 0, 0"
               TextChanged="OnTextChanged" />

        <Label x:Name="helpLabel"
               Text="Phone number must be of the form 555-555-5555, and not begin with a 0 or 1">
            <VisualStateManager.VisualStateGroups>
                <VisualStateGroup Name="ValidityStates">
                    
                    <VisualState Name="Valid">
                        <VisualState.Setters>
                            <Setter Property="TextColor" Value="Transparent" />
                        </VisualState.Setters>
                    </VisualState>

                    <VisualState Name="Invalid" />
                    
                </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>
        </Label>

        <Button x:Name="submitButton"
                Text="Submit"
                FontSize="Large"
                Margin="0, 20"
                VerticalOptions="Center"
                HorizontalOptions="Center">
            <VisualStateManager.VisualStateGroups>
                <VisualStateGroup Name="ValidityStates">
                    
                    <VisualState Name="Valid" />

                    <VisualState Name="Invalid">
                        <VisualState.Setters>
                            <Setter Property="IsEnabled" Value="False" />
                        </VisualState.Setters>
                    </VisualState>
                    
                </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>
        </Button>
    </StackLayout>
</ContentPage>

A marcação VSM é anexada à segunda Label (chamada helpLabel) e à Button (chamada submitButton).VSM markup is attached to the second Label (named helpLabel) and the Button (named submitButton). Há dois Estados mutuamente exclusivos, denominados "válido" e "inválido".There are two mutually-exclusive states, named "Valid" and "Invalid". Observe que cada um dos dois grupos "ValidationState" contém marcas de VisualState para "válido" e "inválido", embora um deles esteja vazio em cada caso.Notice that each of the two "ValidationState" groups contains VisualState tags for both "Valid" and "Invalid", although one of them is empty in each case.

Se o Entry não contiver um número de telefone válido, o estado atual será "inválido" e, portanto, a segunda Label ficará visível e o Button será desabilitado:If the Entry does not contain a valid phone number, then the current state is "Invalid", and so the second Label is visible and the Button is disabled:

Validação de VSM: estado inválidoVSM Validation: Invalid State

Quando um número de telefone válido é inserido, o estado atual se torna "válido".When a valid phone number is entered, then the current state becomes "Valid". A segunda Entry desaparece e a Button agora está habilitada:The second Entry disappears and the Button is now enabled:

Validação de VSM: estado válidoVSM Validation: Valid State

O arquivo code-behind é reponsible para manipular o evento de TextChanged da Entry.The code-behind file is reponsible for handling the TextChanged event from the Entry. O manipulador usa uma expressão regular para determinar se a cadeia de caracteres de entrada é válida ou não.The handler uses a regular expression to determine if the input string is valid or not. O método no arquivo code-behind chamado GoToState chama o método estático VisualStateManager.GoToState para helpLabel e submitButton:The method in the code-behind file named GoToState calls the static VisualStateManager.GoToState method for both helpLabel and submitButton:

public partial class VsmValidationPage : ContentPage
{
    public VsmValidationPage ()
    {
        InitializeComponent ();

        GoToState(false);
    }

    void OnTextChanged(object sender, TextChangedEventArgs args)
    {
        bool isValid = Regex.IsMatch(args.NewTextValue, @"^[2-9]\d{2}-\d{3}-\d{4}$");
        GoToState(isValid);
    }

    void GoToState(bool isValid)
    {
        string visualState = isValid ? "Valid" : "Invalid";
        VisualStateManager.GoToState(helpLabel, visualState);
        VisualStateManager.GoToState(submitButton, visualState);
    }
}

Observe também que o método GoToState é chamado a partir do construtor para inicializar o estado.Notice also that the GoToState method is called from the constructor to initialize the state. Sempre deve haver um estado atual.There should always be a current state. Mas em qualquer lugar no código há qualquer referência ao nome do grupo de estado visual, embora ele seja referenciado no XAML como "ValidationStates" para fins de clareza.But nowhere in the code is there any reference to the name of the visual state group, although it's referenced in the XAML as "ValidationStates" for purposes of clarity.

Observe que o arquivo code-behind deve assumir a conta de cada objeto na página que é afetada por esses Estados visuais e chamar VisualStateManager.GoToState para cada um desses objetos.Notice that the code-behind file must take account of every object on the page that is affected by these visual states, and to call VisualStateManager.GoToState for each of these objects. Neste exemplo, são apenas dois objetos (o Label e o Button), mas podem ser vários outros.In this example, it's only two objects (the Label and the Button), but it could be several more.

Você pode imaginar: se o arquivo code-behind deve fazer referência a cada objeto na página que é afetada por esses Estados visuais, por que não é possível que o arquivo code-behind simplesmente acesse os objetos diretamente?You might wonder: If the code-behind file must reference every object on the page that is affected by these visual states, why can't the code-behind file simply access the objects directly? Certamente poderia.It surely could. No entanto, a vantagem de usar o VSM é que você pode controlar como os elementos visuais reagem para um estado diferente inteiramente no XAML, o que mantém todo o design da interface do usuário em um único local.However, the advantage of using the VSM is that you can control how visual elements react to different state entirely in XAML, which keeps all of the UI design in one location. Isso evita a configuração da aparência visual acessando elementos visuais diretamente do code-behind.This avoids setting visual appearance by accessing visual elements directly from the code-behind.

Pode ser tentador considerar a derivação de uma classe de Entry e, talvez, definir uma propriedade que pode ser definida como uma função de validação externa.It might be tempting to consider deriving a class from Entry and perhaps defining a property that you can set to an external validation function. A classe que deriva de Entry pode então chamar o método VisualStateManager.GoToState.The class that derives from Entry can then call the VisualStateManager.GoToState method. Esse esquema funcionaria bem, mas somente se o Entry fosse o único objeto afetado pelos diferentes Estados visuais.This scheme would work fine, but only if the Entry were the only object affected by the different visual states. Neste exemplo, um Label e um Button também são afetados.In this example, a Label and a Button are also be affected. Não há nenhuma maneira de marcação VSM anexada a um Entry para controlar outros objetos na página e não há nenhuma maneira de marcação VSM anexada a esses outros objetos para fazer referência a uma alteração no estado visual de outro objeto.There is no way for VSM markup attached to an Entry to control other objects on the page, and no way for VSM markup attached to these other objects to reference a change in visual state from another object.

Usando o Gerenciador de estado visual para layout adaptávelUsing the Visual State Manager for adaptive layout

Um aplicativo Xamarin. Forms em execução em um telefone geralmente pode ser exibido em uma taxa de proporção retrato ou paisagem, e um programa Xamarin. Forms em execução na área de trabalho pode ser redimensionado para assumir muitos tamanhos e proporções de proporção diferentes.A Xamarin.Forms application running on a phone can usually be viewed in a portrait or landscape aspect ratio, and a Xamarin.Forms program running on the desktop can be resized to assume many different sizes and aspect ratios. Um aplicativo bem projetado pode exibir seu conteúdo de forma diferente para esses vários fatores forma de página ou janela.A well-designed application might display its content differently for these various page or window form factors.

Essa técnica às vezes é conhecida como layout adaptável.This technique is sometimes known as adaptive layout. Como o layout adaptável apenas envolve os visuais de um programa, ele é um aplicativo ideal do Gerenciador de estado visual.Because adaptive layout solely involves a program's visuals, it is an ideal application of the Visual State Manager.

Um exemplo simples é um aplicativo que exibe uma pequena coleção de botões que afetam o conteúdo do aplicativo.A simple example is an application that displays a small collection of buttons that affect the application's content. No modo retrato, esses botões podem ser exibidos em uma linha horizontal na parte superior da página:In portrait mode, these buttons might be displayed in a horizontal row on the top of the page:

Layout adaptável do VSM: retratoVSM Adaptive Layout: Portrait

No modo paisagem, a matriz de botões pode ser movida para um lado e exibida em uma coluna:In landscape mode, the array of buttons might be moved to one side, and displayed in a column:

Layout adaptável do VSM: paisagemVSM Adaptive Layout: Landscape

De cima para baixo, o programa está em execução no Plataforma Universal do Windows, no Android e no iOS.From top to bottom, the program is running on the Universal Windows Platform, Android, and iOS.

A página de layout adaptável do VSM no exemplo de VsmDemos define um grupo chamado "OrientationStates" com dois estados visuais chamados "retrato" e "paisagem".The VSM Adaptive Layout page in the VsmDemos sample defines a group named "OrientationStates" with two visual states named "Portrait" and "Landscape". (Uma abordagem mais complexa pode ser baseada em várias larguras de página ou janela diferentes.)(A more complex approach might be based on several different page or window widths.)

A marcação VSM ocorre em quatro locais no arquivo XAML.VSM markup occurs in four places in the XAML file. O StackLayout nomeado mainStack contém o menu e o conteúdo, que é um elemento Image.The StackLayout named mainStack contains both the menu and the content, which is an Image element. Este StackLayout deve ter uma orientação vertical no modo retrato e uma orientação horizontal no modo paisagem:This StackLayout should have a vertical orientation in portrait mode and a horizontal orientation in landscape mode:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="VsmDemos.VsmAdaptiveLayoutPage"
             Title="VSM Adaptive Layout">

    <StackLayout x:Name="mainStack">
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup Name="OrientationStates">

                <VisualState Name="Portrait">
                    <VisualState.Setters>
                        <Setter Property="Orientation" Value="Vertical" />
                    </VisualState.Setters>
                </VisualState>

                <VisualState Name="Landscape">
                    <VisualState.Setters>
                        <Setter Property="Orientation" Value="Horizontal" />
                    </VisualState.Setters>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
        
        <ScrollView x:Name="menuScroll">
            <VisualStateManager.VisualStateGroups>
                <VisualStateGroup Name="OrientationStates">
                    
                    <VisualState Name="Portrait">
                        <VisualState.Setters>
                            <Setter Property="Orientation" Value="Horizontal" />
                        </VisualState.Setters>
                    </VisualState>

                    <VisualState Name="Landscape">
                        <VisualState.Setters>
                            <Setter Property="Orientation" Value="Vertical" />
                        </VisualState.Setters>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>
            
            <StackLayout x:Name="menuStack">
                <VisualStateManager.VisualStateGroups>
                    <VisualStateGroup Name="OrientationStates">

                        <VisualState Name="Portrait">
                            <VisualState.Setters>
                                <Setter Property="Orientation" Value="Horizontal" />
                            </VisualState.Setters>
                        </VisualState>

                        <VisualState Name="Landscape">
                            <VisualState.Setters>
                                <Setter Property="Orientation" Value="Vertical" />
                            </VisualState.Setters>
                        </VisualState>
                    </VisualStateGroup>
                </VisualStateManager.VisualStateGroups>

                <StackLayout.Resources>
                    <Style TargetType="Button">
                        <Setter Property="VisualStateManager.VisualStateGroups">
                            <VisualStateGroupList>
                                <VisualStateGroup Name="OrientationStates">

                                    <VisualState Name="Portrait">
                                        <VisualState.Setters>
                                            <Setter Property="HorizontalOptions" Value="CenterAndExpand" />
                                            <Setter Property="Margin" Value="10, 5" />
                                        </VisualState.Setters>
                                    </VisualState>

                                    <VisualState Name="Landscape">
                                        <VisualState.Setters>
                                            <Setter Property="VerticalOptions" Value="CenterAndExpand" />
                                            <Setter Property="HorizontalOptions" Value="Center" />
                                            <Setter Property="Margin" Value="10" />
                                        </VisualState.Setters>
                                    </VisualState>
                                </VisualStateGroup>
                            </VisualStateGroupList>
                        </Setter>
                    </Style>
                </StackLayout.Resources>

                <Button Text="Banana"
                        Command="{Binding SelectedCommand}"
                        CommandParameter="Banana.jpg" />
                
                <Button Text="Face Palm"
                        Command="{Binding SelectedCommand}"
                        CommandParameter="FacePalm.jpg" />
                
                <Button Text="Monkey"
                        Command="{Binding SelectedCommand}"
                        CommandParameter="monkey.png" />
                
                <Button Text="Seated Monkey"
                        Command="{Binding SelectedCommand}"
                        CommandParameter="SeatedMonkey.jpg" />
            </StackLayout>
        </ScrollView>

        <Image x:Name="image"
               VerticalOptions="FillAndExpand"
               HorizontalOptions="FillAndExpand" />
    </StackLayout>
</ContentPage>

O ScrollView interno chamado menuScroll e o StackLayout nomeado menuStack implementam o menu de botões.The inner ScrollView named menuScroll and the StackLayout named menuStack implement the menu of buttons. A orientação desses layouts é oposta à mainStack.The orientation of these layouts is opposite of mainStack. O menu deve ser horizontal no modo retrato e vertical no modo paisagem.The menu should be horizontal in portrait mode and vertical in landscape mode.

A quarta seção da marcação VSM está em um estilo implícito para os próprios botões.The fourth section of VSM markup is in an implicit style for the buttons themselves. Essa marcação define as propriedades VerticalOptions, HorizontalOptions e Margin específicas para as orientações de portait e paisagem.This markup sets VerticalOptions, HorizontalOptions, and Margin properties specific to the portait and landscape orientations.

O arquivo code-behind define a propriedade BindingContext de menuStack para implementar Button comando e também anexa um manipulador ao evento SizeChanged da página:The code-behind file sets the BindingContext property of menuStack to implement Button commanding, and also attaches a handler to the SizeChanged event of the page:

public partial class VsmAdaptiveLayoutPage : ContentPage
{
    public VsmAdaptiveLayoutPage ()
    {
        InitializeComponent ();

        SizeChanged += (sender, args) =>
        {
            string visualState = Width > Height ? "Landscape" : "Portrait";
            VisualStateManager.GoToState(mainStack, visualState);
            VisualStateManager.GoToState(menuScroll, visualState);
            VisualStateManager.GoToState(menuStack, visualState);

            foreach (View child in menuStack.Children)
            {
                VisualStateManager.GoToState(child, visualState);
            }
        };

        SelectedCommand = new Command<string>((filename) =>
        {
            image.Source = ImageSource.FromResource("VsmDemos.Images." + filename);
        });

        menuStack.BindingContext = this;
    }

    public ICommand SelectedCommand { private set; get; }
}

O manipulador de SizeChanged chama VisualStateManager.GoToState para os dois elementos StackLayout e ScrollView e, em seguida, percorre os filhos de menuStack para chamar VisualStateManager.GoToState para os elementos Button.The SizeChanged handler calls VisualStateManager.GoToState for the two StackLayout and ScrollView elements, and then loops through the children of menuStack to call VisualStateManager.GoToState for the Button elements.

Pode parecer que o arquivo code-behind pode tratar as alterações de orientação mais diretamente definindo as propriedades de elementos no arquivo XAML, mas o Gerenciador de estado visual é definitivamente uma abordagem mais estruturada.It may seem as if the code-behind file can handle orientation changes more directly by setting properties of elements in the XAML file, but the Visual State Manager is definitely a more structured approach. Todos os visuais são mantidos no arquivo XAML, onde se tornam mais fáceis de examinar, manter e modificar.All the visuals are kept in the XAML file, where they become easier to examine, maintain, and modify.

Gerenciador de estado visual com Xamarin. UniversityVisual State Manager with Xamarin.University

Vídeo do Gerenciador de estado visual do Xamarin. Forms 3,0Xamarin.Forms 3.0 Visual State Manager video