Infosys Microsoft Alliance and Solutions blog

« Silverlight 2.0 RC0 Installation | Main | Part 2: Manage Page level states with VisualStateManager in Silverlight »

Part 1: Manage Page level states with VisualStateManager in Silverlight

Silverlight 2.0 Beta 2 introduced the concept of Visual State Manager (VSM). If you haven't checked it out still, here are some articles that will get you started.

VSM not only helps keep the looks and behavior of a control separate, it allows you to manage the various states the control can be in, along with the transitions, in a very clean and effective manner. Though most of the examples online today show this in context of a specific control and working with its control template, there is no reason why this can't be applied to the UserControl itself, i.e. at the Page level. You can very easily create custom states for your page and manage transitions between the states. In fact this can actually help reduce the total animations that you may have to write and also simplify the backend code.

In this two part blog post, I will explain this with a small sample. I am assuming basic understanding of Silverlight animations and VSM as well. In this first part I will explore how you would build an application without VSM and in part 2, create a similar experience but with using VSM. 

Let's start with taking a simplistic case where we will have 3 buttons on my Page which act like menu control.  On clicking a particular button, it will animate downwards, thus showing the active button. We will assume that the rest of the page has content filled up based on which button was clicked. To start with the here's the XAML with 3 buttons in a Grid.

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

        <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" RenderTransformOrigin="0.5,0.5" Content="Button 3" Click="btn3_Click">

            <Button.RenderTransform>

                <TransformGroup>

                    <ScaleTransform/>

                    <SkewTransform/>

                    <RotateTransform/>

                    <TranslateTransform/>

                </TransformGroup>

            </Button.RenderTransform>

        </Button>

    </Grid>

Next is to add the required animation so that a button can move to the new location. For this we can use Blend and add Button1Animation, which moves the button down. We use the TranslateTransform property and modify the Y value to 40. The animation storyboard is as below.

        <Storyboard x:Name="Button1Animation">

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

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

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

            </DoubleAnimationUsingKeyFrames>

        </Storyboard>

While this animation moves the button down, we will need another animation to move the button back to its original position when another button is moved down. To do this, Blend offers an easy way by which we can create a duplicate animation and then reverse it from the Objects and Timeline panel. See the figure below.

duplicate.jpg

Using this approach, we get the Button1Animation_Copy animation.

        <Storyboard x:Name="Button1Animation_Copy">

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

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

                <SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="0"/>

            </DoubleAnimationUsingKeyFrames>

        </Storyboard>

On similar lines we can create additional animations for the other two buttons to move them down and then back up. These are as below. 

        <Storyboard x:Name="Button2Animation">

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

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

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

            </DoubleAnimationUsingKeyFrames>

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

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

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

            </DoubleAnimationUsingKeyFrames>

        </Storyboard>

        <Storyboard x:Name="Button2Animation_Copy">

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

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

                <SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="0"/>

            </DoubleAnimationUsingKeyFrames>

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

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

                <SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="0"/>

            </DoubleAnimationUsingKeyFrames>

        </Storyboard>

        <Storyboard x:Name="Button3Animation">

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

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

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

            </DoubleAnimationUsingKeyFrames>

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

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

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

            </DoubleAnimationUsingKeyFrames>

        </Storyboard>

        <Storyboard x:Name="Button3Animation_Copy">

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

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

                <SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="0"/>

            </DoubleAnimationUsingKeyFrames>

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

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

                <SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="0"/>

            </DoubleAnimationUsingKeyFrames>

        </Storyboard>

The next step is to stitch this together so that when we click a button, it moves down and the one already down moves back to its original position. For this the code will be something like below.

    public partial class Page : UserControl

    {

        enum MenuButton

        {

            None,

            One,

            Two,

            Three

        }

 

        MenuButton _current;

        public Page()

        {

            InitializeComponent();

            _current = MenuButton.None;

        }

 

        private void btn1_Click(object sender, RoutedEventArgs e)

        {

            //if the current button is different than the one clicked, animate it back and then animate this button in

            if (_current != MenuButton.One)

            {

                AnimateOut(_current);

                Button1Animation.Begin();

                _current = MenuButton.One;

            }

        }

 

        private void btn2_Click(object sender, RoutedEventArgs e)

        {

            //if the current button is different than the one clicked, animate it back and then animate this button in

            if (_current != MenuButton.Two)

            {

                AnimateOut(_current);

                Button2Animation.Begin();

                _current = MenuButton.Two;

            }

        }

 

        private void btn3_Click(object sender, RoutedEventArgs e)

        {

            //if the current button is different than the one clicked, animate it back and then animate this button in

            if (_current != MenuButton.Three)

            {

                AnimateOut(_current);

                Button3Animation.Begin();

                _current = MenuButton.Three;

            }

        }

 

        //animate the button back to its original location

        private void AnimateOut(MenuButton btn)

        {

            switch (btn)

            {

                case MenuButton.One:

                    Button1Animation_Copy.Begin();

                    break;

                case MenuButton.Two:

                    Button2Animation_Copy.Begin();

                    break;

                case MenuButton.Three:

                    Button3Animation_Copy.Begin();

                    break;

            }

        }

    }

If you run the application now and click any button, you will see it animate down and the previous button will animate and move back. This concludes part 1. In part 2 we will look at how using VSM, we can simplify this application and reduce the amount of code we have to write.

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