20 - Control VisualStateManager y Grid


Hemos visto que mediante el control Grid podemos ubicar el contenido en distintas celdas en la pantalla. Ahora utilizando el control VisualStateManager podemos fijar el contenido de las celdas dependiendo del ancho de pantalla.

Una situación muy común es mostrar datos en distintas columnas cuando tenemos una pantalla muy ancho, pero si estamos ejecutando la aplicación en un dispositivo con un ancho limitado como un celular podemos reubicar el contenido en una sola columna.

Problema

Elaborar una interfaz que muestre el contenido en tres columnas para dispositivos que tienen un ancho de más de 1024 píxeles y en el caso que tenga menos ancho se muestre todo en una única columna.

En la pantalla el contenido debe mostrarse según el ancho del dispositivo con alguno de estos dos layout:

VisualStateManager

Y en un dispositivo angosto debe aparecer:

VisualStateManager

Como primer paso creamos un nuevo proyecto llamado "Proyecto27" seleccionando desde el menú de opciones del Visual Studio: Archivo -> Nuevo -> Proyecto

En este problema todo debe ser codificado en el archivo MainPage.xaml utilizando "Adaptative Triggers":

<Page
    x:Class="Proyecto27.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Proyecto27"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="VisualStateGroup">
                <VisualState x:Name="pc">
                    <VisualState.StateTriggers>
                        <AdaptiveTrigger MinWindowWidth="1024" />
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                        <Setter Target="contenido1.(Grid.Row)" Value="0" />
                        <Setter Target="contenido1.(Grid.Column)" Value="0" />
                        <Setter Target="contenido2.(Grid.Row)" Value="0" />
                        <Setter Target="contenido2.(Grid.Column)" Value="1" />
                        <Setter Target="contenido3.(Grid.Row)" Value="0" />
                        <Setter Target="contenido3.(Grid.Column)" Value="2" />

                        <Setter Target="contenido1.(Grid.ColumnSpan)" Value="1" />
                        <Setter Target="contenido2.(Grid.ColumnSpan)" Value="1" />
                        <Setter Target="contenido3.(Grid.ColumnSpan)" Value="1" />
                    </VisualState.Setters>
                </VisualState>
                <VisualState x:Name="telefono">
                    <VisualState.StateTriggers>
                        <AdaptiveTrigger MinWindowWidth="0" />
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                        <Setter Target="contenido1.(Grid.Row)" Value="0" />
                        <Setter Target="contenido1.(Grid.Column)" Value="0" />
                        <Setter Target="contenido2.(Grid.Row)" Value="1" />
                        <Setter Target="contenido2.(Grid.Column)" Value="0" />
                        <Setter Target="contenido3.(Grid.Row)" Value="2" />
                        <Setter Target="contenido3.(Grid.Column)" Value="0" />

                        <Setter Target="contenido1.(Grid.ColumnSpan)" Value="3" />
                        <Setter Target="contenido2.(Grid.ColumnSpan)" Value="3" />
                        <Setter Target="contenido3.(Grid.ColumnSpan)" Value="3" />
                    </VisualState.Setters>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="auto"/>
                <RowDefinition Height="auto" />
                <RowDefinition Height="auto"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>

            <StackPanel Name="contenido1" Margin="20,20,0,0">
                <TextBlock FontSize="40">
                    C#
                </TextBlock>
                <TextBlock  TextWrapping="Wrap">
                El objetivo de este tutorial es iniciarse en el arte de la programación desde cero 
                empleando el lenguaje C# desarrollado por Microsoft.
                Nos conviene utilizar este lenguaje para iniciarnos si nuestro objetivo final
                será desarrollar aplicaciones de escritorio, web o móviles (Windows Phone) en un futuro.
                </TextBlock>
            </StackPanel>
            <StackPanel Name="contenido2" Margin="20,20,0,0">
                <TextBlock FontSize="40">
                    Java
                </TextBlock>
                <TextBlock TextWrapping="Wrap">
                 Java
                 El objetivo de este tutorial es iniciarse en el arte de la programación desde cero 
                 empleando el lenguaje Java como soporte para el desarrollo de aplicaciones.
                 El lenguaje Java está presente en múltiples sistemas operativos y dispositivos de escritorio y móviles.
                 Nos conviene utilizar este lenguaje para iniciarnos si nuestro objetivo final será desarrollar 
                 aplicaciones móviles para Android.
                </TextBlock>
            </StackPanel>
            <StackPanel Name="contenido3" Margin="20,20,0,0">
                <TextBlock FontSize="40">
                    C++
                </TextBlock>
                <TextBlock TextWrapping="Wrap">
                 El tutorial está desarrollado pensando en iniciarse en la programación desde cero empleando
                 el lenguaje C++ como soporte para la implementación de programas.
                 Nos conviene utilizar este lenguaje para iniciarnos si nuestro objetivo final será desarrollar
                 aplicaciones de bajo nivel o software de base.
                </TextBlock>
            </StackPanel>
        </Grid>
    </Grid>
</Page>

Definimos tres StackPanel con el contenido que se muestra, el primer StackPanel muestra dos TextBlock:

            <StackPanel Name="contenido1" Margin="20,20,0,0">
                <TextBlock FontSize="40">
                    C#
                </TextBlock>
                <TextBlock  TextWrapping="Wrap">
                El objetivo de este tutorial es iniciarse en el arte de la programación desde cero 
                empleando el lenguaje C# desarrollado por Microsoft.
                Nos conviene utilizar este lenguaje para iniciarnos si nuestro objetivo final
                será desarrollar aplicaciones de escritorio, web o móviles (Windows Phone) en un futuro.
                </TextBlock>
            </StackPanel>

El segundo StackPanel:

            <StackPanel Name="contenido2" Margin="20,20,0,0">
                <TextBlock FontSize="40">
                    Java
                </TextBlock>
                <TextBlock TextWrapping="Wrap">
                 Java
                 El objetivo de este tutorial es iniciarse en el arte de la programación desde cero 
                 empleando el lenguaje Java como soporte para el desarrollo de aplicaciones.
                 El lenguaje Java está presente en múltiples sistemas operativos y dispositivos de escritorio y móviles.
                 Nos conviene utilizar este lenguaje para iniciarnos si nuestro objetivo final será desarrollar 
                 aplicaciones móviles para Android.
                </TextBlock>
            </StackPanel>

El último StackPanel:

            <StackPanel Name="contenido3" Margin="20,20,0,0">
                <TextBlock FontSize="40">
                    C++
                </TextBlock>
                <TextBlock TextWrapping="Wrap">
                 El tutorial está desarrollado pensando en iniciarse en la programación desde cero empleando
                 el lenguaje C++ como soporte para la implementación de programas.
                 Nos conviene utilizar este lenguaje para iniciarnos si nuestro objetivo final será desarrollar
                 aplicaciones de bajo nivel o software de base.
                </TextBlock>
            </StackPanel>

Hemos definido un Name para cada uno de los StackPanel: "contenido1", "contenido2" y "contenido3" para hacer referencia a los mismos en el VisualStateManager.

Como podemos ver no le hemos asignado las filas y columnas donde se deben mostrar los StackPanel.

Si se ejecuta en un dispositivo que tiene un ancho de menos de 1024 píxeles se ejecuta el bloque del VisualStateManager:

                <VisualState x:Name="telefono">
                    <VisualState.StateTriggers>
                        <AdaptiveTrigger MinWindowWidth="0" />
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                        <Setter Target="contenido1.(Grid.Row)" Value="0" />
                        <Setter Target="contenido1.(Grid.Column)" Value="0" />
                        <Setter Target="contenido2.(Grid.Row)" Value="1" />
                        <Setter Target="contenido2.(Grid.Column)" Value="0" />
                        <Setter Target="contenido3.(Grid.Row)" Value="2" />
                        <Setter Target="contenido3.(Grid.Column)" Value="0" />

                        <Setter Target="contenido1.(Grid.ColumnSpan)" Value="3" />
                        <Setter Target="contenido2.(Grid.ColumnSpan)" Value="3" />
                        <Setter Target="contenido3.(Grid.ColumnSpan)" Value="3" />
                    </VisualState.Setters>
                </VisualState>

Donde mediante la referencia a cada StackPanel accedemos a la propiedad Row y Column del Grid, por ejemplo el primer StackPanel lo ubicamos en la fila 0 y columna 0 (son obligatorios los paréntesis luego de hacer referencia a la variable contenido1):

                        <Setter Target="contenido1.(Grid.Row)" Value="0" />
                        <Setter Target="contenido1.(Grid.Column)" Value="0" />

El segundo StackPanel lo ubicamos también el la columna 0 pero en la fila 1 del Grid:

                        <Setter Target="contenido2.(Grid.Row)" Value="1" />
                        <Setter Target="contenido2.(Grid.Column)" Value="0" />

El tercer StackPanel lo ubicamos en la columna 0 y la fila 2:

                        <Setter Target="contenido3.(Grid.Row)" Value="2" />
                        <Setter Target="contenido3.(Grid.Column)" Value="0" />

Como creamos una Grid de 3 filas y tres columnas luego expandimos los StackPanel para que ocupen las tres columnas:

                        <Setter Target="contenido1.(Grid.ColumnSpan)" Value="3" />
                        <Setter Target="contenido2.(Grid.ColumnSpan)" Value="3" />
                        <Setter Target="contenido3.(Grid.ColumnSpan)" Value="3" />
VisualStateManager

Si ejecutamos la aplicación en un dispositivo que tiene un ancho de más de 1024 píxeles debemos ubicar los tres StackPanel en la misma fila 0:

                <VisualState x:Name="pc">
                    <VisualState.StateTriggers>
                        <AdaptiveTrigger MinWindowWidth="1024" />
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                        <Setter Target="contenido1.(Grid.Row)" Value="0" />
                        <Setter Target="contenido1.(Grid.Column)" Value="0" />
                        <Setter Target="contenido2.(Grid.Row)" Value="0" />
                        <Setter Target="contenido2.(Grid.Column)" Value="1" />
                        <Setter Target="contenido3.(Grid.Row)" Value="0" />
                        <Setter Target="contenido3.(Grid.Column)" Value="2" />

                        <Setter Target="contenido1.(Grid.ColumnSpan)" Value="1" />
                        <Setter Target="contenido2.(Grid.ColumnSpan)" Value="1" />
                        <Setter Target="contenido3.(Grid.ColumnSpan)" Value="1" />
                    </VisualState.Setters>
                </VisualState>
VisualStateManager

Este proyecto lo puede descargar en un zip desde este enlace :Proyecto27.zip

Retornar