O xamarin. Forms Visual State ManagerThe Xamarin.Forms Visual State Manager

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

O Gerenciador de VSM (Visual State) é nova no xamarin. Forms 3.0.The Visual State Manager (VSM) is new in Xamarin.Forms 3.0. O VSM fornece uma maneira estruturada para fazer alterações visual para a interface do usuário 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 este XAML inclui a marcação que descreve como o Gerenciador de estado Visual afeta os 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. Um modo de exibição do xamarin. Forms, como um Button pode ter várias aparências diferentes dependendo do seu estado subjacente — se ele estiver desabilitado, ou pressionado ou se tem o 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.

Estados visuais são coletados no grupos de estado visual.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. Estados visuais e grupos de estado visual 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"
  • "Com foco""Focused"

Há suporte para esse grupo de estados visuais 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 os estados visuais, como este artigo irá demonstrar.You can also define your own visual state groups and visual states, as this article will demonstrate.

Observação

Os desenvolvedores de xamarin. Forms familiarizados com gatilhos estão cientes de que os gatilhos também podem fazer alterações aos visuais na interface do usuário com base em alterações em Propriedades da exibição ou o 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, usando 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 Gerenciador de estado Visual foi introduzido em ambientes baseados em XAML do Windows para minimizar 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. Os estados visuais dentro de um grupo de estado visual com o VSM, sempre são 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 pode alterar a aparência visual de um modo de exibição, se o modo de exibição é normal ou desabilitado ou se 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 o estados comuns.These are known as the common states.

Por exemplo, suponha que você tenha um Entry modo de exibição em sua página, e você deseja que a aparência visual do Entry alterar 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 uma rosa em segundo plano quando o Entry está desabilitado.The Entry should have a pink background when the Entry is disabled.
  • O Entry deve ter um plano de fundo verde-limão normalmente.The Entry should have a lime background normally.
  • O Entry deve expandir para duas vezes sua altura normal quando ele tem 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 você pode defini-la em um estilo se apliquem a vários modos de exibição.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 duas próximas seções descrevem essas abordagens.The next two sections describe these approaches.

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

Anexar marcação VSM para um Entry exibir, primeiro separe o Entry nas marcas de início e término:To attach VSM markup to an Entry view, first separate the Entry into start and end tags:

<Entry FontSize="18">

</Entry>

Isso tenha dado a um tamanho de fonte explícito porque um dos Estados usará o FontSize propriedade para dobrar o tamanho do texto no 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, inserir 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 associável anexada definida pelo VisualStateManager classe.VisualStateGroups is an attached bindable property defined by the VisualStateManager class. (Para obter mais informações sobre propriedades vinculáveis anexadas, consulte o artigo propriedades anexadas.) Isso é como o VisualStateGroups propriedade está anexada a Entry objeto.(For more information on attached bindable properties, see the article Attached properties.) This is how the VisualStateGroups property is attached to the Entry object.

O VisualStateGroups propriedade é do tipo VisualStateGroupList , que é uma coleção de VisualStateGroup objetos.The VisualStateGroups property is of type VisualStateGroupList, which is a collection of VisualStateGroup objects. Dentro de VisualStateManager.VisualStateGroups marcas, inserir um par de VisualStateGroup marcas para cada grupo de estados visuais que 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 o VisualStateGroup marca tem um x:Name atributo que indica o nome do grupo.Notice that the VisualStateGroup tag has an x:Name attribute indicating the name of the group. O VisualStateGroup classe define um Name propriedade 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 tanto 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.

O VisualStateGroup classe define uma propriedade chamada States , que é uma coleção de VisualState objetos.The VisualStateGroup class defines a property named States, which is a collection of VisualState objects. States é o propriedade de conteúdo dos VisualStateGroups para que você possa incluir o VisualState marcas diretamente entre o VisualStateGroup marcas.States is the content property of VisualStateGroups so you can include the VisualState tags directly between the VisualStateGroup tags. (Conteúdo de propriedades são discutidas no artigo sintaxe de 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. Eles também podem ser identificados 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 Setter objetos.VisualState defines a property named Setters, which is a collection of Setter objects. Essas são as mesmas Setter objetos que podem ser usados em um Style objeto.These are the same Setter objects that you use in a Style object.

Setters está não a propriedade content de VisualState, portanto, é necessário incluir marcas de elemento de propriedade para o Setters propriedade: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 Setter objetos entre cada par de Setters marcas.You can now insert one or more Setter objects between each pair of Setters tags. Esses são os Setter objetos 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 Setter marca 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 uma Setter objeto deve ser feito por uma propriedade associável.Any property referenced by a Setter object must be backed by a bindable property.

Marcação semelhante a esta é a base para o VSM na exibição página na VsmDemos programa de exemplo.Markup similar to this is the basis of the VSM on View page in the VsmDemos sample program. A página inclui três Entry modos de exibição, mas apenas um segundo tem a marcação VSM anexada a ele: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 um DataTrigger como parte de seu Trigger coleção.Notice that the second Entry also has a DataTrigger as part of its Trigger collection. Isso faz com que o Entry será desabilitada até que algo seja digitado à 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, Android e Universal Windows Platform (UWP):Here's the page at startup running on iOS, Android, and the Universal Windows Platform (UWP):

VSM no modo de exibição: desabilitadoVSM on View: Disabled

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

Quando você digitar um texto à terceira Entry, o segundo Entry alterna para o estado "Normal" e o plano de fundo agora está 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 no modo de exibição: NormalVSM on View: Normal

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

VSM no modo de exibição: focadoVSM on View: Focused

Observe que o Entry não retém o plano de fundo verde-limão quando ele recebe 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 não definidas.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 o Entry está habilitado e não tem o foco de entrada.It means that the Entry is enabled and does not have input focus.

Se você quiser que o Entry para ter um plano de fundo verde-limão em estado "Focalizado", adicione outro Setter para que o 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 eles Setter objetos funcione corretamente, um VisualStateGroup deve conter VisualState objetos para todos os estados no grupo.In order for these Setter objects to work properly, a VisualStateGroup must contain VisualState objects for all the states in that group. Se não houver um estado visual que não tem nenhum Setter objetos, incluí-lo mesmo assim 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 de Gerenciador de estado visual em um estiloVisual State Manager markup in a style

Ele geralmente é necessário compartilhar a mesma marcação de Gerenciador de estado Visual entre dois 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 um Style definição.In this case, you'll want to put the markup in a Style definition.

Aqui está implícita existente Style para o Entry elementos na VSM no modo de exibição página: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 Setter marcas para o VisualStateManager.VisualStateGroups propriedade associável 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 está Value, portanto, o valor da Value propriedade pode ser especificada diretamente dentro de marcas.The content property for Setter is Value, so the value of the Value property can be specified directly within those tags. Se a 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 VisualStateGroup objetos: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 de antes.The remainder of the VSM markup is the same as before.

Aqui está o VSM em estilo página 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 exibições nesta página respondem da mesma maneira para 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 "Focalizado" inclui agora uma segunda Setter que dá a cada Entry um verde-limão em segundo plano também quando ele tem o 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

Cada classe que deriva de VisualElement dá suporte a três estados comuns "Normal", "Voltada para" e "Disabled".Every class that derives from VisualElement supports the three common states "Normal", "Focused", and "Disabled". Internamente, o VisualElement classe detecta quando ele está se tornando habilitado ou desabilitado, ou focalizado ou sem foco e chama estático VisualStateManager.GoToState método: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");

Isso é o único código do Gerenciador de estado Visual que você encontrará o VisualElement classe.This is the only Visual State Manager code that you'll find in the VisualElement class. Porque GoToState é chamado para cada objeto com base em cada classe que deriva de VisualElement, você pode usar o Gerenciador de estado Visual com qualquer VisualElement objeto 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 estados visuais "CommonStates" não é explicitamente referenciado nos VisualElement.Interestingly, the name of the visual state group "CommonStates" is not explicitly referenced in VisualElement. O nome do grupo não é parte da API para o Gerenciador de estado Visual.The group name is not part of the API for the Visual State Manager. Dentro de um a dois programa de exemplo mostrado até agora, você pode alterar o nome do grupo de "CommonStates" para qualquer outra coisa, e o programa ainda funcionará.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 no grupo.The group name is merely a general description of the states in that group. É implicitamente entendido que os estados visuais em qualquer grupo são mutuamente exclusivos: uma 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, você 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 do arquivo code-behind da sua classe de página.Most often you'll make this call from the code-behind file of your page class.

O VSM validação página de VsmDemos exemplo 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 Label elementos, uma 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>

Marcação VSM está anexada à segunda Label (chamado helpLabel) e o Button (chamado submitButton).VSM markup is attached to the second Label (named helpLabel) and the Button (named submitButton). Há dois estados mutuamente exclusivas, chamados de "Válido" e "Inválido".There are two mutually-exclusive states, named "Valid" and "Invalid". Observe que cada um dos dois grupos de "ValidationState" contém VisualState marcas para "Válido" e "Inválido", embora um deles está 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 contém um número de telefone válido, em seguida, o estado atual é "Inválido" e, portanto, a segunda Label está visível e o Button está 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:

VSM validação: Estado inválidoVSM Validation: Invalid State

Quando um número de telefone válido for inserido, em seguida, 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á habilitado:The second Entry disappears and the Button is now enabled:

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

O arquivo code-behind é responsável para a manipulação de TextChanged eventos do 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 em que o arquivo code-behind chamado GoToState chama estático VisualStateManager.GoToState método para ambos 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 GoToState método é chamado de 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 não no código há qualquer referência ao nome do grupo de estados visuais, embora ela é referenciada 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 levar em conta todos os objetos 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, ele é apenas dois objetos (o Label e o Button), mas poderia ser vários mais.In this example, it's only two objects (the Label and the Button), but it could be several more.

Você talvez esteja se perguntando: se o arquivo code-behind deve fazer referência a todos os objetos na página que é afetado por esses estados visuais, por que não o arquivo code-behind simplesmente acessar 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? Obviamente, foi possível.It surely could. No entanto, a vantagem de usar o VSM é que você pode controlar os elementos visuais como reagir a estado diferente inteiramente em XAML, que mantém todos o design de 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 aparência visual de configuração por meio de acessar elementos visuais diretamente no code-behind.This avoids setting visual appearance by accessing visual elements directly from the code-behind.

Pode ser tentador considere derivar uma classe de Entry e talvez definindo uma propriedade que você pode definir uma função externa de validação.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 , em seguida, pode chamar o VisualStateManager.GoToState método.The class that derives from Entry can then call the VisualStateManager.GoToState method. Esse esquema funcionaria bem, mas somente se o Entry foram o único objeto afetado pelos estados visuais diferentes.This scheme would work fine, but only if the Entry were the only object affected by the different visual states. Neste exemplo, uma Label e um Button também são afetados.In this example, a Label and a Button are also be affected. Não é possível para marcação VSM anexados a um Entry para controlar outros objetos na página e nenhuma maneira para marcação VSM anexados a esses outros objetos para fazer referência a uma alteração de 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 o layout adaptávelUsing the Visual State Manager for adaptive layout

Um xamarin. Forms aplicativo em execução em um telefone geralmente pode ser exibido em um retrato ou paisagem taxa de proporção e um programa de xamarin. Forms em execução na área de trabalho pode ser redimensionada para assumir muitos tamanhos diferentes e taxas de proporção.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 diferentes para esses vários fatores de formulário de página ou janela.A well-designed application might display its content differently for these various page or window form factors.

Às vezes, essa técnica é conhecida como adaptável layout.This technique is sometimes known as adaptive layout. Como layout adaptável envolve apenas elementos 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 do VSM adaptável: 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 do VSM adaptável: PaisagemVSM Adaptive Layout: Landscape

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

O Layout adaptável do VSM página de VsmDemos exemplo define um grupo chamado "OrientationStates" com dois estados visuais denominados "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.)

Marcação VSM ocorre em quatro lugares 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 Image elemento.The StackLayout named mainStack contains both the menu and the content, which is an Image element. Isso 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>

Interno ScrollView nomeado menuScroll e o StackLayout denominada menuStack implementar 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 é o oposto de 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 de marcação VSM está em um estilo implícito para os botões em si.The fourth section of VSM markup is in an implicit style for the buttons themselves. Essa marcação define VerticalOptions, HorizontalOptions, e Margin propriedades específicas para as orientações portait e paisagem.This markup sets VerticalOptions, HorizontalOptions, and Margin properties specific to the portait and landscape orientations.

Os conjuntos de arquivos de lógica de BindingContext propriedade de menuStack para implementar Button dos comandos e também anexa um manipulador para o SizeChanged eventos 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 SizeChanged chamadas do manipulador VisualStateManager.GoToState para os dois StackLayout e ScrollView elementos e, em seguida, executa um loop pelos filhos de menuStack chamar VisualStateManager.GoToState para o Button elementos.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 como se o arquivo code-behind pode lidar com alterações de orientação mais diretamente, definindo as propriedades dos 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 elementos visuais são mantidos no arquivo XAML, onde eles se tornam mais fácil de examinar, manutenção 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

Xamarin. Forms 3.0 Visual State Manager, por Xamarin UniversityXamarin.Forms 3.0 Visual State Manager, by Xamarin University