> For the complete documentation index, see [llms.txt](https://elguerre.gitbook.io/de0an/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://elguerre.gitbook.io/de0an/capitulo-9-la-construccion.-navegacion-y-configuracion-de-usuario/visualstatemanager.md).

# VisualStateManager

En el **Capítulo 8**, vimos el uso del **VisualStateManager** para crear la plantilla de botones circulares denominada “RoundedButtonStyle”. Esta técnica nos permitió definir diferentes estados visuales para los botones, mejorando tanto su apariencia como su interactividad. Siguiendo la misma idea, en esta sección vamos a aplicar el **VisualStateManager** en la página “Main” para optimizar la interacción con el usuario. Específicamente, nuestro objetivo es informar al usuario durante la entrada a la aplicación mientras se carga la página con los proyectos y tareas.

## Implementación Avanzada del VisualStateManager

El **VisualStateManager** es una herramienta poderosa en XAML que permite definir y gestionar diferentes estados visuales de la interfaz de usuario de manera eficiente. A diferencia de los converters, el **VisualStateManager** ofrece mejoras significativas en el rendimiento, especialmente cuando se trabaja con listas grandes. Utilizar un converter de colores para el estado seleccionado y no seleccionado puede resultar en tiempos de refresco considerablemente más largos, lo que afecta negativamente la experiencia del usuario.

### Modificación de la Plantilla “RoundedButtonStyle”

Profundizaremos en la plantilla de “RoundedButtonStyle” para ilustrar cómo el **VisualStateManager** puede mejorar la interactividad y el rendimiento de los botones en la página principal.

```xml
<Style x:Key="RoundedButtonStyle" TargetType="Button">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Grid>
                    <Ellipse x:Name="ButtonBackground" Fill="{TemplateBinding Background}" />
                    <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsPointerOver" Value="True">
                        <Setter TargetName="ButtonBackground" Property="Fill" Value="LightGray"/>
                    </Trigger>
                    <Trigger Property="IsPressed" Value="True">
                        <Setter TargetName="ButtonBackground" Property="Fill" Value="DarkGray"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
```

En este ejemplo, los triggers dentro del **ControlTemplate** permiten cambiar el color de fondo del botón en función de la interacción del usuario. Sin embargo, esta aproximación puede volverse ineficiente cuando se aplica a una gran cantidad de botones en listas extensas.

### Beneficios del VisualStateManager

* **Rendimiento Mejorado:** El uso del **VisualStateManager** mejora el rendimiento en comparación con los converters tradicionales. Esto es especialmente notable en listas grandes donde la cantidad de controles y triggers puede impactar negativamente en los tiempos de renderizado.
* **Flexibilidad y Mantenimiento:** Definir estados visuales de manera centralizada facilita el mantenimiento y la escalabilidad de la interfaz de usuario. Permite realizar cambios globales en los estilos sin necesidad de modificar múltiples converters o triggers individuales.

### Ejemplo de Uso del VisualStateManager en la Página Main

A continuación, se muestra cómo implementar el **VisualStateManager** en la página principal para gestionar el estado de carga de datos, proporcionando una retroalimentación visual al usuario durante la inicialización de la aplicación.

```xml
<Page
    x:Class="MyApp.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MyApp"
    xmlns:i="using:Microsoft.Xaml.Interactivity"
    xmlns:core="using:Microsoft.Xaml.Interactions.Core"
    mc:Ignorable="d">

    <Grid>
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="LoadingStates">
                <VisualState x:Name="Loading">
                    <Storyboard>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="LoadingPanel" Storyboard.TargetProperty="Visibility">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
                        </ObjectAnimationUsingKeyFrames>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPanel" Storyboard.TargetProperty="Visibility">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
                        </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                </VisualState>
                <VisualState x:Name="Loaded">
                    <Storyboard>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="LoadingPanel" Storyboard.TargetProperty="Visibility">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
                        </ObjectAnimationUsingKeyFrames>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPanel" Storyboard.TargetProperty="Visibility">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
                        </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>

        <!-- Panel de Carga -->
        <StackPanel x:Name="LoadingPanel" VerticalAlignment="Center" HorizontalAlignment="Center" Visibility="Collapsed">
            <ProgressRing IsActive="True" Width="50" Height="50"/>
            <TextBlock Text="Cargando datos..." Margin="0,10,0,0" FontSize="16" HorizontalAlignment="Center"/>
        </StackPanel>

        <!-- Contenido Principal -->
        <StackPanel x:Name="ContentPanel" Visibility="Collapsed">
            <!-- Contenido de la página principal -->
            <Hub x:Name="MainHub" HeaderTemplate="{Binding Source={StaticResource AppHeader}}">
                <!-- Secciones del Hub -->
            </Hub>
        </StackPanel>
    </Grid>
</Page>
```

En este ejemplo, se definen dos estados visuales: `Loading` y `Loaded`. Durante la carga de datos, se activa el estado `Loading`, mostrando el panel de carga y ocultando el contenido principal. Una vez que los datos están completamente cargados, se cambia al estado `Loaded`, ocultando el panel de carga y mostrando el contenido principal.

## Comparación con Converters

El uso de **VisualStateManager** ofrece ventajas significativas sobre el uso de converters para gestionar estados visuales:

* **Rendimiento:** Los **VisualStateManagers** son más eficientes ya que manejan los cambios de estado de manera declarativa y optimizada por el motor de renderizado de XAML. En contraste, los converters pueden requerir procesamiento adicional, especialmente en listas grandes, lo que puede resultar en tiempos de refresco más largos.
* **Mantenimiento:** Los estados visuales definidos con **VisualStateManager** son más fáciles de mantener y escalar. Cambiar un estado visual en una ubicación centralizada afecta a todos los controles que lo utilizan, reduciendo la duplicación de código y simplificando el mantenimiento.
* **Flexibilidad:** El **VisualStateManager** permite definir animaciones y transiciones complejas entre estados de manera más sencilla y fluida, lo que no es tan directo con converters.

**IMPORTANTE:** Existen diversas técnicas para crear plantillas de datos dinámicas, tales como:

* **Converters:** Permiten convertir valores de una propiedad a otra durante el enlace de datos.
* **VisualStateManager:** Gestiona diferentes estados visuales de los controles de manera eficiente.
* **DataTriggerBehavior:** Permite activar acciones basadas en condiciones específicas de datos.
* **DataTemplateSelector:** Permite seleccionar dinámicamente una plantilla de datos basada en condiciones lógicas.

## Conclusión

El **VisualStateManager** es una herramienta esencial para gestionar de manera eficiente los estados visuales de la interfaz de usuario en aplicaciones UWP. Al aprovechar esta funcionalidad, no solo mejoramos el rendimiento de la aplicación, sino que también simplificamos el mantenimiento y escalabilidad de nuestros estilos y plantillas. Comparado con métodos tradicionales como los converters, el **VisualStateManager** ofrece una solución más robusta y optimizada para manejar la interactividad y los cambios de estado en la interfaz de usuario.
