Using VisualStateManager/Storyboard in MVVM


A recurring problem with MVVM is how to incorporate animations in a nice MVVM way. The problem is that StoryBoards need to be started from the view, since they are usually configured in XAML. This means that the ViewModel needs a reference to the view, in order to tell it when the animation should start. Keeping a reference from the ViewModel to the View is obviously “not done” in the MVVM pattern. In this post I’m going to show how you can use the VisualStateManager to start animations and incorporate it in the MVVM pattern, without keeping a reference from the ViewModel to the View.

1st a create VisualStates.cs class which implement an attached property

    public static class VisualStates
    {
       public static readonly DependencyProperty CurrentStateProperty =
           DependencyProperty.RegisterAttached("CurrentState", typeof(String), typeof(VisualStates), new PropertyMetadata(TransitionToState));

        public static string GetCurrentState(DependencyObject obj)
        {
            return (string)obj.GetValue(CurrentStateProperty);
        }

        public static void SetCurrentState(DependencyObject obj, string value)
        {
            obj.SetValue(CurrentStateProperty, value);
        }

        private static void TransitionToState(object sender, DependencyPropertyChangedEventArgs args)
        {
            Control c = sender as Control;
            if(c != null)
            {
                VisualStateManager.GoToState(c, (string)args.NewValue, true);
            }
            else
            {
                throw new ArgumentException("CurrentState is only supported on the Control type");
            }
        }
    }

2nd in the ViewModel provide a Property that will fire and NotifyPropertyChanged event

        private string _currentState;
        public string CurrentState
        {
            get
            {
                return _currentState;
            }
            set
            {
                if (value != _currentState)
                {
                    _currentState = value;
                    OnPropertyChanged(new PropertyChangedEventArgs("CurrentState"));
                }
            }
        }

Finally in the View, attached VisualStates to the UserControl and Bind the Property in the ViewModel that will cause the change in Visual State

<UserControl
    ...
    xmlns:mvvm="clr-namespace:MVVMSupport;assembly=MVVMSupport"
    DataContext="{StaticResource mainPageViewModel}"
    mvvm:VisualStates.CurrentState="{Binding CurrentState}"
    >
    <Grid x:Name="LayoutRoot" Background="White">
    	<VisualStateManager.VisualStateGroups>
    		<VisualStateGroup x:Name="States">
                    ...

Via http://blogs.infosupport.com/blogs/alexb/archive/2010/04/02/silverlight-4-using-the-visualstatemanager-for-state-animations-with-mvvm.aspx

An alternative without using Attached Property is using Blend 4’s PropertyChangedTrigger or DataTrigger

  • PropertyChangedTrigger will fire whenever there is a change in value
  • DataTrigger allow you to specify a condition and it will fire only when the condition matches

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s