Infosys Microsoft Alliance and Solutions blog

« Part 1: Manage Page level states with VisualStateManager in Silverlight | Main | Midori, RedHawk, MinSafe? »

Part 2: Manage Page level states with VisualStateManager in Silverlight

In part 1 we saw how using basic storyboarding/animation capabilities in Silverlight, we created a simple application where buttons move to new location when clicked and move back when another button is clicked. In this part we will see how using VSM, we can build the same capabilities with lesser animations and lesser code. The complete code (including code for part 1) can be downloaded from here - Download file. Note that I have built this using SL 2.0 RC0, but the concepts explained here will work with Beta 2 bits as well.

Let's add a new page to the application and call it VSMPage.xaml. We will build the same UI but with VSM to manage the animations on the page. Copy the page content (inside of the LayoutRoot grid) from Page.xaml to this page to get the 3 buttons.  To add the VSM related states, we will use Blend. In Blend, first create a new StateGroup and then add states to it to identify the 3 states related to the 3 button. See the figure below. The intention is that each state relates to that particular button being animated and moved down.

states.jpg

Like in part 1, we we want the transitions between each state to always take 0.3 sec and hence we add that as global value at StateGroup level.

                <vsm:VisualStateGroup.Transitions>

                    <vsm:VisualTransition GeneratedDuration="00:00:00.3"/>

                </vsm:VisualStateGroup.Transitions>

 To add the actual state transition, we can now click each state and add the transition. Note that unlike regular animations, the state transitions are typically recorded for time 0 itself. The actual time taken for the transition is managed separately by setting the state transition. Here, we have taken 0.3 sec for all transitions. I can however set this at individual state transition as well. The Button1State animation looks like below

                <vsm:VisualState x:Name="Button1State">

                    <Storyboard>

                        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="btn1" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)">

                            <SplineDoubleKeyFrame KeyTime="00:00:00" Value="40"/>

                        </DoubleAnimationUsingKeyFrames>

                    </Storyboard>

                </vsm:VisualState>

Checkout the breaking changes between Beta 2 and RC0 to know the differences introduced for VSM and state transitions. Back to the article and we can now add similar transitions for the rest of the states and this will finally look like the following

<UserControl x:Class="SLTestApp.VSMPage"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"

   Width="400" Height="300" xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows">

    <Grid x:Name="LayoutRoot" Background="White">

        <vsm:VisualStateManager.VisualStateGroups>

            <vsm:VisualStateGroup x:Name="MenuStates">

                <vsm:VisualStateGroup.Transitions>

                    <vsm:VisualTransition GeneratedDuration="00:00:00.3"/>

                </vsm:VisualStateGroup.Transitions>

                <vsm:VisualState x:Name="Button1State">

                    <Storyboard>

                        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="btn1" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)">

                            <SplineDoubleKeyFrame KeyTime="00:00:00" Value="40"/>

                        </DoubleAnimationUsingKeyFrames>

                    </Storyboard>

                </vsm:VisualState>

                <vsm:VisualState x:Name="Button2State">

                    <Storyboard>

                        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="btn2" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)">

                            <SplineDoubleKeyFrame KeyTime="00:00:00" Value="-72"/>

                        </DoubleAnimationUsingKeyFrames>

                        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="btn2" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)">

                            <SplineDoubleKeyFrame KeyTime="00:00:00" Value="40"/>

                        </DoubleAnimationUsingKeyFrames>

                    </Storyboard>

                </vsm:VisualState>

                <vsm:VisualState x:Name="Button3State">

                    <Storyboard>

                        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="btn3" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)">

                            <SplineDoubleKeyFrame KeyTime="00:00:00" Value="-142"/>

                        </DoubleAnimationUsingKeyFrames>

                        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="btn3" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)">

                            <SplineDoubleKeyFrame KeyTime="00:00:00" Value="40"/>

                        </DoubleAnimationUsingKeyFrames>

                    </Storyboard>

                </vsm:VisualState>

            </vsm:VisualStateGroup>

        </vsm:VisualStateManager.VisualStateGroups>

        <Button HorizontalAlignment="Left" Margin="8,8,0,0" x:Name="btn1" VerticalAlignment="Top" RenderTransformOrigin="0.5,0.5" Content="Button 1" Click="btn1_Click">

            <Button.RenderTransform>

                <TransformGroup>

                    <ScaleTransform/>

                    <SkewTransform/>

                    <RotateTransform/>

                    <TranslateTransform/>

                </TransformGroup>

            </Button.RenderTransform>

        </Button>

        <Button HorizontalAlignment="Left" Margin="80,8,0,0" x:Name="btn2" VerticalAlignment="Top" RenderTransformOrigin="0.5,0.5" Content="Button 2" Click="btn2_Click">

            <Button.RenderTransform>

                <TransformGroup>

                    <ScaleTransform/>

                    <SkewTransform/>

                    <RotateTransform/>

                    <TranslateTransform/>

                </TransformGroup>

            </Button.RenderTransform>

        </Button>

        <Button HorizontalAlignment="Left" Margin="150,8,0,0" x:Name="btn3" VerticalAlignment="Top" Content="Button 3" d:LayoutOverrides="Width" Click="btn3_Click">

            <Button.RenderTransform>

                <TransformGroup>

                    <ScaleTransform/>

                    <SkewTransform/>

                    <RotateTransform/>

                    <TranslateTransform/>

                </TransformGroup>

            </Button.RenderTransform>

        </Button>

 

    </Grid>

</UserControl>

The only piece left now is to run these transitions at appropriate time and for that we will handle the button click events and write a single line to invoke the VSM's GoTo method. The following is how the code behind file looks like.

    public partial class VSMPage : UserControl

    {

        public VSMPage()

        {

            InitializeComponent();

        }

 

        private void btn1_Click(object sender, RoutedEventArgs e)

        {

            VisualStateManager.GoToState(this, "Button1State", true);

        }

 

        private void btn2_Click(object sender, RoutedEventArgs e)

        {

            VisualStateManager.GoToState(this, "Button2State", true);

        }

 

        private void btn3_Click(object sender, RoutedEventArgs e)

        {

            VisualStateManager.GoToState(this, "Button3State", true);

        }

    }

Build and run the application (do make sure that you have modified the App.xaml.cs to point to VSMPage in the Application_Startup event handler) and you will see the animations working just like before. Unlike earlier case however, we have not written any animation to move the button back to its original place. That is automatically handled by VSM when managing the state transitions. Additionally, this also means the code behind logic is greatly simplified and we no longer need to track which is the currently selected button. All we do is invoke the VSM's GoTo method. The third parameter signifies that we want to play the storyboard associated with this state change. 

So next time you are building a Silverlight application think how you can define various states for your application and use VSM to effectively transition between them.

Comments

I read the last blog which was really useful. I tried to use Visual State Manager in the WinApp in Blend. But I get an error when i write vsm:VisualStateManager.VisualStateGroups

Can you help me in this matter? Waiting for your reply.

Pritish, when you say WinApp, you mean Silverlight application or something else? And can you share details of your error?

Post a comment

(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)

Please key in the two words you see in the box to validate your identity as an authentic user and reduce spam.

Subscribe to this blog's feed

Follow us on

Blogger Profiles

Infosys on Twitter