Xamarin.Forms Administrador de estado visual

Ejemplo de descarga Descarga del ejemplo

Use el Administrador de estado visual para realizar cambios en los elementos XAML en función de los estados visuales establecidos a partir del código.

Visual State Manager (VSM) proporciona una manera estructurada de realizar cambios visuales en la interfaz de usuario desde el código. En la mayoría de los casos, la interfaz de usuario de la aplicación se define en XAML, y este XAML incluye marcado que describe cómo el Administrador de estado visual afecta a los objetos visuales de la interfaz de usuario.

EL VSM presenta el concepto de estados visuales. Una vista como una puede tener varias apariencias visuales diferentes en función de su estado subyacente, ya sea si está deshabilitada, presionada o tiene el foco Xamarin.FormsButton de entrada. Estos son los estados del botón.

Los estados visuales se recopilan en grupos de estados visuales. Todos los estados visuales dentro de un grupo de estados visuales son mutuamente excluyentes. Tanto los estados visuales como los grupos de estados visuales se identifican mediante cadenas de texto simples.

El Xamarin.Forms Administrador de estado visual define un grupo de estado visual denominado "CommonStates" con los siguientes estados visuales:

  • "Normal"
  • "Deshabilitado"
  • "Con foco"
  • "Seleccionado"

Este grupo de estado visual es compatible con todas las clases que derivan de VisualElement , que es la clase base para y ViewPage .

También puede definir sus propios grupos de estados visuales y estados visuales, como se mostrará en este artículo.

Nota:

Xamarin.FormsLos desarrolladores familiarizados con los desencadenadores son conscientes de que los desencadenadores también pueden realizar cambios en los objetos visuales de la interfaz de usuario en función de los cambios en las propiedades de una vista o la activación de eventos. Xamarin.Forms Sin embargo, el uso de desencadenadores para tratar varias combinaciones de estos cambios puede resultar bastante confuso. Históricamente, Visual State Manager se introdujo en Windows entornos basados en XAML para mitigar la confusión resultante de combinaciones de estados visuales. Con VSM, los estados visuales dentro de un grupo de estados visuales siempre son mutuamente excluyentes. En cualquier momento, solo un estado de cada grupo es el estado actual.

Estados comunes

El Administrador de estado visual permite incluir marcado en el archivo XAML que puede cambiar la apariencia visual de una vista si la vista es normal, deshabilitada o tiene el foco de entrada. Estos se conocen como los estados comunes.

Por ejemplo, supongamos que tiene una vista en la página y desea que la apariencia visual de EntryEntry cambie de las maneras siguientes:

  • debe Entry tener un fondo rosa cuando está Entry deshabilitado.
  • el Entry debe tener un fondo de verde verde normalmente.
  • debe Entry expandirse al doble de su altura normal cuando tiene el foco de entrada.

Puede adjuntar el marcado VSM a una vista individual o puede definirlo en un estilo si se aplica a varias vistas. En las dos secciones siguientes se describen estos enfoques.

Marcado de VSM en una vista

Para adjuntar el marcado VSM a una Entry vista, primero separe las Entry etiquetas inicial y final:

<Entry FontSize="18">

</Entry>

Se le asigna un tamaño de fuente explícito porque uno de los estados usará la propiedad para duplicar el tamaño FontSize del texto en Entry .

A continuación, VisualStateManager.VisualStateGroups inserte etiquetas entre esas etiquetas:

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

    </VisualStateManager.VisualStateGroups>
</Entry>

VisualStateGroups es una propiedad enlazable adjunta definida por la VisualStateManager clase . (Para obtener más información sobre las propiedades enlazables adjuntas, vea el artículo Propiedades adjuntas). Así es como VisualStateGroups se adjunta la propiedad al objeto Entry .

La VisualStateGroups propiedad es de tipo , que es una colección de objetos VisualStateGroupListVisualStateGroup . Dentro de VisualStateManager.VisualStateGroups las etiquetas, inserte un par de etiquetas para cada grupo de estados VisualStateGroup visuales que quiera incluir:

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

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

Observe que la VisualStateGroup etiqueta tiene un atributo que indica el nombre del x:Name grupo. La VisualStateGroup clase define una propiedad que puede usar en su Name lugar:

<VisualStateGroup Name="CommonStates">

Puede usar o x:Name pero no ambos en el mismo Name elemento.

La clase define una propiedad VisualStateGroup denominada Xamarin_Forms VisualStateGroup _VisualStateGroup_States" data-linktype="absolute-path">States , que VisualState es una colección de objetos . States es la States , por lo que puede incluir las VisualStateGroupsVisualState etiquetas directamente entre las VisualStateGroup etiquetas. (Las propiedades de contenido se de abordan en el artículo Sintaxis XAML esencial).

El siguiente paso consiste en incluir un par de etiquetas para cada estado visual de ese grupo. También se pueden identificar mediante x:Name o 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>

VisualStatedefine una propiedad denominada Xamarin_Forms VisualState _VisualState_Setters" data-linktype="absolute-path">Setters , que es una colección de Setter objetos . Estos son los mismos Setter objetos que se usan en un objeto Style .

Setters no Setters propiedad content de , por lo que es necesario incluir VisualState etiquetas de elemento de propiedad para la Setters propiedad :

<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>

Ahora puede insertar uno o varios Setter objetos entre cada par de Setters etiquetas. Estos son los Setter objetos que definen los estados visuales descritos anteriormente:

<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 etiqueta indica el valor de una propiedad determinada cuando ese estado es actual. Cualquier propiedad a la que hace referencia Setter un objeto debe estar copiada por una propiedad enlazable.

Un marcado similar a este es la base de vsm en la página Ver del programa de ejemplo VsmDemos. La página incluye tres vistas, pero solo la segunda tiene asociado el marcado Entry VSM:

<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 el segundo Entry también tiene como parte de su DataTriggerTrigger colección. Esto hace que Entry se deshabilite hasta que se escriba algo en el tercer Entry . Esta es la página de inicio que se ejecuta en iOS, Android y la Plataforma Windows universal (UWP):

VSM en la vista:

El estado visual actual es "Deshabilitado", por lo que el fondo del segundo Entry es rosa en las pantallas de iOS y Android. La implementación de UWP Entry de no permite establecer el color de fondo cuando está Entry deshabilitado.

Al escribir algo de texto en el tercero, el segundo cambia al estado EntryEntry "Normal" y el fondo ahora es de color verde:

VSM en la vista: VSM normal

Al tocar el segundo Entry , obtiene el foco de entrada. Cambia al estado "Enfocado" y se expande al doble de su altura:

VSM en la vista:

Observe que no Entry conserva el fondo de la cal cuando obtiene el foco de entrada. A medida que Visual State Manager cambia entre los estados visuales, las propiedades establecidas por el estado anterior no se establecen. Tenga en cuenta que los estados visuales son mutuamente excluyentes. El estado "Normal" no significa únicamente que Entry está habilitado. Esto significa que está Entry habilitado y no tiene el foco de entrada.

Si desea que tenga un fondo de verde verde en el estado Entry "Enfocado", agregue otro a Setter ese estado visual:

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

Para que estos Setter objetos funcionen correctamente, debe contener objetos para VisualStateGroup todos los estados de ese VisualState grupo. Si hay un estado visual que no tiene ningún Setter objeto, inscluyéndolo de todos modos como una etiqueta vacía:

<VisualState x:Name="Normal" />

Marcado de Visual State Manager en un estilo

A menudo es necesario compartir el mismo marcado de Visual State Manager entre dos o más vistas. En este caso, querrá colocar el marcado en una Style definición.

Este es el elemento Style implícito existente para los elementos de la página EntryStyle

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

Agregue Setter etiquetas para la VisualStateManager.VisualStateGroups propiedad enlazable adjunta:

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

    </Setter>
</Style>

La propiedad content de es , por lo que el valor Setter de la propiedad se puede especificar directamente dentro de esas ValueValue etiquetas. Esa propiedad es de tipo VisualStateGroupList :

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

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

Dentro de esas etiquetas puede incluir uno de los objetos VisualStateGroup siguientes:

<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>

El resto del marcado de VSM es el mismo que antes.

Esta es la página VSM en estilo que muestra el marcado de VSM completo:

<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>

Ahora todas las Entry vistas de esta página responden de la misma manera a sus estados visuales. Observe también que el estado "Enfocado" ahora incluye un segundo que proporciona a cada uno un fondo de verde Setter también cuando tiene el foco de Entry entrada:

VSM en estilo

Estados visuales en Xamarin.Forms

En la tabla siguiente se enumeran los estados visuales definidos en Xamarin.Forms :

Clase States Más información
Button Pressed Estados visuales de botón
CheckBox IsChecked Estados visuales de CheckBox
CarouselView DefaultItem, CurrentItem, PreviousItem, NextItem Estados visuales de CarouselView
ImageButton Pressed Estados visuales imageButton
RadioButton Checked, Unchecked Estados visuales de RadioButton
Switch On, Off Cambio de los estados visuales
VisualElement Normal, Disabled, Focused, Selected Estados comunes

Se puede acceder a cada uno de estos estados a través del grupo de estado visual denominado CommonStates .

Además, implementa CollectionView el Selected estado . Para obtener más información, vea Cambiar el color del elemento seleccionado.

Establecer el estado en varios elementos

En los ejemplos anteriores, los estados visuales se asociaban y operaban en elementos únicos. Sin embargo, también es posible crear estados visuales que estén asociados a un único elemento, pero que establezcan propiedades en otros elementos dentro del mismo ámbito. Esto evita tener que repetir estados visuales en cada elemento en el que operan los estados.

El Setter tipo tiene una propiedad, de tipo , que representa el elemento de destino que va a manipular para TargetName un estado stringSetter visual. Cuando se define la propiedad , establece el del TargetName elemento definido en en SetterPropertyTargetNameValue :

<Setter TargetName="label"
        Property="Label.TextColor"
        Value="Red" />

En este ejemplo, un Label con nombre tendrá su propiedad establecida en labelTextColorRed . Al establecer la TargetName propiedad , debe especificar la ruta de acceso completa a la propiedad en Property . Por lo tanto, para TextColor establecer la propiedad en , se especifica como LabelPropertyLabel.TextColor .

Nota:

Cualquier propiedad a la que hace referencia Setter un objeto debe estar copiada por una propiedad enlazable.

La página VSM con Setter TargetName del ejemplo VsmDemos muestra cómo establecer el estado en varios elementos, desde un único grupo de estado visual. El archivo XAML consta de StackLayout un elemento que contiene un elemento , y LabelEntryButton :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="VsmDemos.VsmSetterTargetNamePage"
             Title="VSM with Setter TargetName">
    <StackLayout Margin="10">
        <Label Text="What is the capital of France?" />
        <Entry x:Name="entry"
               Placeholder="Enter answer" />
        <Button Text="Reveal answer">
            <VisualStateManager.VisualStateGroups>
                <VisualStateGroup x:Name="CommonStates">
                    <VisualState x:Name="Normal" />
                    <VisualState x:Name="Pressed">
                        <VisualState.Setters>
                            <Setter Property="Scale"
                                    Value="0.8" />
                            <Setter TargetName="entry"
                                    Property="Entry.Text"
                                    Value="Paris" />
                        </VisualState.Setters>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>
        </Button>
    </StackLayout>
</ContentPage>

El marcado VSM está asociado a StackLayout . Hay dos estados mutuamente excluyentes, denominados "Normal" y "Pressed", con cada estado que contiene VisualState etiquetas.

El estado "Normal" está activo cuando no se presiona y se puede especificar Button una respuesta a la pregunta:

VsM Setter TargetName: normal state

El estado "Presionado" se activa cuando Button se presiona :

VsM Setter TargetName: Pressed State

"Pressed" especifica que cuando se presiona , su propiedad se cambiará del valor predeterminado VisualStateButton de Scale 1 a 0,8. Además, el Entry con nombre tendrá su propiedad establecida en entryText París. Por lo tanto, el resultado es que, cuando se presiona , se vuelve a escalar para que sea ligeramente más pequeño Button y Entry muestra París. A continuación, cuando se libera, se vuelve a escalar a su valor predeterminado de 1 y muestra ButtonEntry cualquier texto especificado previamente.

Importante

Las rutas de acceso de propiedad no se admiten actualmente Setter en los elementos que especifican la propiedad TargetName .

Definición de sus propios estados visuales

Todas las clases que derivan de VisualElement admiten los estados comunes "Normal", "Focused" y "Disabled". Además, la CollectionView clase admite el estado "Selected". Internamente, xamarin.forms /blob/master/ Xamarin.Forms . Core/VisualElement.cs" data-linktype="external">class detects when it's becoming enabled or disabled, or VisualElement focused or unfocused, and calls the static Xamarin_Forms Xamarin.Forms _VisualStateManager_GoToState_ Xamarin_Forms _VisualElement_System_String_" data-linktype="absolute-path">VisualStateManager.GoToState method:

VisualStateManager.GoToState(this, "Focused");

Este es el único código de Visual State Manager que encontrará en la VisualElement clase . Dado que se llama a para cada objeto basado en cada clase que deriva de , puede usar el Administrador de estado visual con cualquier objeto GoToState para responder a estos VisualElementVisualElement cambios.

Es interesante que no se haga referencia explícitamente al nombre del grupo de estado visual "CommonStates" en VisualElement . El nombre del grupo no forma parte de la API de Visual State Manager. Dentro de uno de los dos programas de ejemplo mostrados hasta ahora, puede cambiar el nombre del grupo de "CommonStates" a cualquier otra cosa y el programa seguirá funcionando. El nombre del grupo es simplemente una descripción general de los estados de ese grupo. Se entiende implícitamente que los estados visuales de cualquier grupo son mutuamente excluyentes: un estado y solo un estado están actuales en cualquier momento.

Si desea implementar sus propios estados visuales, deberá llamar a VisualStateManager.GoToState desde el código. La mayoría de las veces se realiza esta llamada desde el archivo de código subyacente de la clase de página.

La página Validación de VSM del ejemplo VsmDemos muestra cómo usar Visual State Manager en relación con la validación de entrada. El archivo XAML consta de StackLayout un elemento que contiene dos Label elementos, , y EntryButton :

<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 x:Name="stackLayout"
                 Padding="10, 10">
            <VisualStateManager.VisualStateGroups>
                <VisualStateGroup Name="ValidityStates">
                    <VisualState Name="Valid">
                        <VisualState.Setters>
                            <Setter TargetName="helpLabel"
                                    Property="Label.TextColor"
                                    Value="Transparent" />
                            <Setter TargetName="entry"
                                    Property="Entry.BackgroundColor"
                                    Value="Lime" />
                        </VisualState.Setters>
                    </VisualState>
                    <VisualState Name="Invalid">
                        <VisualState.Setters>
                            <Setter TargetName="entry"
                                    Property="Entry.BackgroundColor"
                                    Value="Pink" />
                            <Setter TargetName="submitButton"
                                    Property="Button.IsEnabled"
                                    Value="False" />
                        </VisualState.Setters>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>
        <Label Text="Enter a U.S. phone number:"
               FontSize="Large" />
        <Entry x:Name="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" />
        <Button x:Name="submitButton"
                Text="Submit"
                FontSize="Large"
                Margin="0, 20"
                VerticalOptions="Center"
                HorizontalOptions="Center" />
    </StackLayout>
</ContentPage>

El marcado VSM está asociado a StackLayout (denominado stackLayout ). Hay dos estados mutuamente excluyentes, denominados "Válido" y "No válido", con cada estado que contiene VisualState etiquetas.

Si no contiene un número de teléfono válido, el estado actual es "Invalid" (No válido) y, por tanto, tiene un fondo rosa, el segundo está visible y está EntryEntryLabelButton deshabilitado:

Validación de VSM: validación de

Cuando se introduce un número de teléfono válido, el estado actual pasa a ser "Válido". obtiene Entry un fondo de cal, el segundo desaparece y ahora está LabelButton habilitado:

Validación de VSM: validación de

El archivo de código subyacente es responsable de controlar el TextChanged evento desde Entry . El controlador usa una expresión regular para determinar si la cadena de entrada es válida o no. El método del archivo de código subyacente denominado GoToState llama al método estático para VisualStateManager.GoToStatestackLayout :

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(stackLayout, visualState);
    }
}

Observe también que se GoToState llama al método desde el constructor para inicializar el estado. Siempre debe haber un estado actual. Pero en el código no hay ninguna referencia al nombre del grupo de estados visuales, aunque en XAML se hace referencia a él como "ValidationStates" para mayor claridad.

Observe que el archivo de código subyacente solo debe tener en cuenta el objeto de la página que define los estados visuales y llamar VisualStateManager.GoToState a para este objeto. Esto se debe a que ambos estados visuales tienen como destino varios objetos de la página.

Podría preguntarse: Si el archivo de código subyacente debe hacer referencia al objeto de la página que define los estados visuales, ¿por qué el archivo de código subyacente no puede acceder directamente a este y a otros objetos? Podría ser posible. Sin embargo, la ventaja de usar VSM es que puedes controlar cómo reaccionan los elementos visuales a un estado diferente completamente en XAML, lo que mantiene todo el diseño de la interfaz de usuario en una ubicación. Esto evita establecer la apariencia visual mediante el acceso a elementos visuales directamente desde el código subyacente.

Desencadenadores de estado visual

Los estados visuales admiten desencadenadores de estado, que son un grupo especializado de desencadenadores que definen las condiciones en las que VisualState se debe aplicar .

Los desencadenadores de estado se agregan a Xamarin_Forms _VisualState_StateTriggers" data-linktype="absolute-path">StateTriggers colección de un VisualState . Esta colección puede contener un único desencadenador de estado o varios desencadenadores de estado. Se aplicará una clase VisualState cuando cualquier desencadenador de estado de la colección esté activo.

Al usar desencadenadores de estado para controlar los estados visuales, Xamarin.Forms usa las siguientes reglas de prioridad para determinar qué desencadenador, y la clase VisualState correspondiente, se activará:

  1. Cualquier desencadenador derivado de StateTriggerBase.
  2. Activado AdaptiveTrigger debido a la Xamarin_Forms AdaptiveTrigger _AdaptiveTrigger_MinWindowWidth" data-linktype="absolute-path">condición que se MinWindowWidth cumple.
  3. Activado AdaptiveTrigger debido a la Xamarin_Forms AdaptiveTrigger _AdaptiveTrigger_MinWindowHeight" data-linktype="absolute-path">condición MinWindowHeight que se cumple.

Si hay varios desencadenadores activos simultáneamente (por ejemplo, dos desencadenadores personalizados), tiene prioridad el primer desencadenador declarado en el marcado.

Para obtener más información sobre desencadenadores de estado, vea Desencadenadores de estado.

Uso de Visual State Manager para el diseño adaptable

Una aplicación que se ejecuta en un teléfono normalmente se puede ver en una relación de aspecto vertical u horizontal, y se puede cambiar el tamaño de un programa que se ejecuta en el escritorio para asumir muchos tamaños y relaciones de aspecto Xamarin.FormsXamarin.Forms diferentes. Una aplicación bien diseñada podría mostrar su contenido de forma diferente para estos distintos factores de forma de página o ventana.

Esta técnica se conoce a veces como diseño adaptable. Dado que el diseño adaptable implica únicamente los objetos visuales de un programa, es una aplicación ideal de Visual State Manager.

Un ejemplo sencillo es una aplicación que muestra una pequeña colección de botones que afectan al contenido de la aplicación. En modo vertical, estos botones pueden mostrarse en una fila horizontal en la parte superior de la página:

Diseño adaptable de VSM: diseño

En modo horizontal, la matriz de botones puede moverse a un lado y mostrarse en una columna:

Diseño adaptable de VSM: diseño

De arriba abajo, el programa se ejecuta en universal Windows Platform, Android e iOS.

La página Diseño adaptable de VSM del ejemplo VsmDemos define un grupo denominado "OrientationStates" con dos estados visuales denominados "Vertical" y "Horizontal". (Un enfoque más complejo puede basarse en varios anchos de página o ventana diferentes).

El marcado VSM se produce en cuatro lugares del archivo XAML. El StackLayout elemento con nombre contiene el menú y el mainStack contenido, que es un elemento Image . Debe StackLayout tener una orientación vertical en modo vertical y una orientación horizontal en modo horizontal:

<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>

Los elementos ScrollView con nombre interno y con nombre implementan el menú de menuScrollStackLayoutmenuStack botones. La orientación de estos diseños es opuesta a mainStack . El menú debe ser horizontal en modo vertical y vertical en modo horizontal.

La cuarta sección del marcado VSM está en un estilo implícito para los propios botones. Este marcado establece VerticalOptions las propiedades , y específicas de las HorizontalOptionsMargin orientaciones vertical y horizontal.

El archivo de código subyacente establece la propiedad de para implementar comandos y también asocia un controlador BindingContext al evento de la menuStackButtonSizeChanged página:

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; }
}

El controlador llama a los dos elementos y y, a SizeChangedVisualStateManager.GoToStateStackLayoutScrollView continuación, menuStackVisualStateManager.GoToStateButton recorre en bucle los elementos secundarios de para llamar a los elementos .

Puede parecer que el archivo de código subyacente puede controlar los cambios de orientación más directamente estableciendo propiedades de elementos en el archivo XAML, pero visual State Manager es definitivamente un enfoque más estructurado. Todos los objetos visuales se conservan en el archivo XAML, donde son más fáciles de examinar, mantener y modificar.

Visual State Manager con Xamarin.University

3.0 Vídeo de Visual State Manager