Cómo iniciar Storyboards desde XAML con Behaviors SDK en Windows 8.1

sábado, 3 de mayo de 2014

Windows 8.1

Introducción

En Windows 8.1 la forma de iniciar las animaciones Storyboard se ha visto restringida con respecto a Silverlight y WPF.

Vamos a realizar un ejemplo de tener una imagen y cuando el ratón pasa por encima, deslizamos un panel hacia abajo con información de la imagen. Vamos a ver como haríamos esto con WPF y luego con Windows 8.1 tanto desde Code-Behind como desde XAML.




Start storyboard from XAML in Windows 8.1

Ejemplo en WPF

En WPF se puede iniciar animaciones desde código XAML utilizando BeginStoryBoard que es un TriggerAction que se puede combinar con EventTrigger para lanzar la animación cuando se produce un evento en el control. Vemos el ejemplo en WPF

        <Border x:Name="BorderContainer" >
            <Border.Triggers>
                <EventTrigger  RoutedEvent="MouseEnter">
                    <BeginStoryboard>
                        <Storyboard >
                            <DoubleAnimation Storyboard.TargetName="InfoPanel"
                                                     Storyboard.TargetProperty="Height"
                                                     Duration="0:0:0.5" From="0" 
                                                     To="300" />
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
                <EventTrigger  RoutedEvent="MouseLeave">
                    <BeginStoryboard>
                        <Storyboard x:Name="PointerExitedStoryboard">
                            <DoubleAnimation Storyboard.TargetName="InfoPanel"
                                                     Storyboard.TargetProperty="Height"
                                                     Duration="0:0:0" From="300" 
                                                     To="0" />
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
            </Border.Triggers>

            <Grid Height="225" Width="300">

                <Image Source="images/isla_saona.jpg" Stretch="Uniform"/>

                <!--InfoPanel-->
                <Border x:Name="InfoPanel" Grid.Row="1" VerticalAlignment="Top" Padding="5"
                                            Background="#E53DC7E6" Height="0">
                    <TextBlock Padding="20" Foreground="White" TextWrapping="Wrap">
                        <Run>
                            Isla Saona:
                        </Run>
                        <LineBreak/> <LineBreak/>
                        <Run>
                            La Isla Saona es la más grande de las islas pertenecientes a la República Dominicana. Forma parte de la Provincia de La Altagracia. Es parte del Parque Nacional del Este.
                        </Run>
                    </TextBlock>
                </Border>


            </Grid>
        </Border>

Todo el proceso lo hemos realizado desde código XAML utilizando EventTrigger y BeginStoryboard.

Ejemplo en Windows 8.1 con Code-Behind

Sin embargo en Windows 8.1 el inicio de animaciones desde XAML solo se puede realizar con el evento Loaded y este se ha mantenido solo por motivo de compatibilidad con Silverlight, pero Microsoft recomienda utilizar Visual States para los casos donde se utilizan triggers en WPF y Silverlight para lanzar animaciones.

El problema es que cuando la animación que queremos lanzar no pertenece a un control sino a un FrameworkElement, estos no tienen Visual States, cómo puede ser el border contenedor de la imagen.

Una solución es definir el Storyboard dentro de la sección de recursos del parent y crear un handler en el Code-Behind de la página.

Veamos el mismo ejemplo en Windows 8.1 utilizando Code-Behind.
        <Border x:Name="BorderContainer" PointerEntered="BorderContainer_PointerEntered"
                PointerExited="BorderContainer_PointerExited">
            <Border.Resources>
                <Storyboard x:Name="ShowPanel">
                    <DoubleAnimation Storyboard.TargetName="InfoPanel"
                                                     Storyboard.TargetProperty="Height"
                                                     Duration="0:0:0.5" From="0" 
                                                     To="300" EnableDependentAnimation="True"/>
                </Storyboard>
                <Storyboard x:Name="ClosePanel">
                    <DoubleAnimation Storyboard.TargetName="InfoPanel"
                                                Storyboard.TargetProperty="Height"
                                                Duration="0:0:0" From="300" 
                                                To="0" EnableDependentAnimation="True"/>
                </Storyboard>

            </Border.Resources>

            <Grid Height="225" Width="300">

                <Image Source="images/isla_saona.jpg" Stretch="Uniform"/>

                <!--InfoPanel-->
                <Border x:Name="InfoPanel" Grid.Row="1" VerticalAlignment="Top" Padding="5"
                                            Background="#E53DC7E6" Height="0">
                    <TextBlock Padding="20" Foreground="White" TextWrapping="Wrap">
                        <Run>
                            Isla Saona:
                        </Run>
                        <LineBreak/> <LineBreak/>
                        <Run>
                            La Isla Saona es la más grande de las islas pertenecientes a la República Dominicana. Forma parte de la Provincia de La Altagracia. Es parte del Parque Nacional del Este.
                        </Run>
                    </TextBlock>
                </Border>


            </Grid>
        </Border>

        private void BorderContainer_PointerEntered(object sender, PointerRoutedEventArgs e)
        {
            var storyboard = (Storyboard)(sender as FrameworkElement).Resources["ShowPanel"];
            storyboard.Begin();
        }

        private void BorderContainer_PointerExited(object sender, PointerRoutedEventArgs e)
        {
            var storyboard = (Storyboard)(sender as FrameworkElement).Resources["ClosePanel"];
            storyboard.Begin();
        }

Pero de esta forma no estamos realizando todo el código desde XAML.

Ejemplo en Windows 8.1 con Behaviors SDK

Ahora con la llegada de Behaviors SDK en Windows 8.1 vamos a poder iniciar animaciones Storyboard desde XAML. Ya escribi un post sobre una de las características de esta libreria para invocar comandos del ViewModel desde la vista.

Ahora vamos a utilizar CallMethodAction con el que se puede invocar un método del ViewModel enlazado o también de un control que tengamos en la vista.

Vamos a ver como sería el ejemplo con Behaviors SDK.

Primero tenemos que añadir la referencia a Behaviors SDK, para hacerlo tenemos que ir a la sección extensiones.


Añadimos los namespaces necesarios
    xmlns:interactivity="using:Microsoft.Xaml.Interactivity"    
    xmlns:core="using:Microsoft.Xaml.Interactions.Core"

Y ahora el código xaml
<Border x:Name="BorderContainer">
            <Border.Resources>
                <Storyboard x:Name="ShowPanel">
                    <DoubleAnimation Storyboard.TargetName="InfoPanel"
                                                     Storyboard.TargetProperty="Height"
                                                     Duration="0:0:0.5" From="0" 
                                                     To="300" EnableDependentAnimation="True"/>
                </Storyboard>
                <Storyboard x:Name="ClosePanel">
                    <DoubleAnimation Storyboard.TargetName="InfoPanel"
                                                Storyboard.TargetProperty="Height"
                                                Duration="0:0:0" From="300" 
                                                To="0" EnableDependentAnimation="True"/>
                </Storyboard>

            </Border.Resources>
            <interactivity:Interaction.Behaviors>
                <core:EventTriggerBehavior EventName="PointerEntered">
                    <core:CallMethodAction TargetObject="{Binding ElementName=ShowPanel}" MethodName="Begin"/>
                </core:EventTriggerBehavior>
                <core:EventTriggerBehavior EventName="PointerExited">
                    <core:CallMethodAction TargetObject="{Binding ElementName=ClosePanel}" MethodName="Begin"/>
                </core:EventTriggerBehavior>
            </interactivity:Interaction.Behaviors>
            <Grid Height="225" Width="300">

                <Image Source="images/isla_saona.jpg" Stretch="Uniform"/>

                <!--InfoPanel-->
                <Border x:Name="InfoPanel" Grid.Row="1" VerticalAlignment="Top" Padding="5"
                                            Background="#E53DC7E6" Height="0">
                    <TextBlock Padding="20" Foreground="White" TextWrapping="Wrap">
                        <Run>
                            Isla Saona:
                        </Run>
                        <LineBreak/> <LineBreak/>
                        <Run>
                            La Isla Saona es la más grande de las islas pertenecientes a la República Dominicana. Forma parte de la Provincia de La Altagracia. Es parte del Parque Nacional del Este.
                        </Run>
                    </TextBlock>
                </Border>


            </Grid>
        </Border>

Mediante la combinación de EventTriggerBehavior y CallMethodAction podemos realizar lo mismo que hacíamos en el ejemplo con CodeBehind, pero todo desde XAML.

Código fuente

Libros Relacionados

Windows 8.1 Apps with XAML and C# Unleashed

Programming Windows: Writing Windows 8 Apps With C# and XAML

Desarrollo en Windows 8 y Windows Phone 8 con XAML y C#

1 comentario:

  1. Muy buen post!, es interesante este tema de las animaciones en WPF, me gustaría que publicaras más post sobre otras animaciones que pueden realizarse en XAML.

    Gracias y saludos!

    ResponderEliminar