MVVM Friendly Visual State Management with Windows Phone 7

27 May 2011

First, the problem. We want to be able to bind to and trigger an animation in the View from the View Model in a zero touch fashion. The use case I’m taking here is displaying a Progress Bar control and having it fade in/out, in this instance using a Visual State Manager.

There are plenty of pointers on how to do this with WPF and Silverlight, but not so many clear examples on Windows Phone.

So here’s our view, containing a PerformanceProgressBar (you are using this right?) which is animated off and on.

 <Grid x:Name="LayoutRoot">
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="VisualStateGroup">
                <VisualState x:Name="Shown">
                    <Storyboard>
                        <DoubleAnimation Storyboard.TargetName="ProgressBar" AutoReverse="False" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="0:0:0.5"/>
                    </Storyboard>
                </VisualState>
                <VisualState x:Name="Hidden">
                    <Storyboard>
                        <DoubleAnimation Storyboard.TargetName="ProgressBar" AutoReverse="False" Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="0:0:0.5"/>
                    </Storyboard>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>

        <toolkit:PerformanceProgressBar Opacity="0" x:Name="ProgressBar" IsIndeterminate="true"  />

    </Grid>

Now let’s take a look at the control’s code behind. What you will notice here is that we are in code setting up a Binding to a custom Dependency Property we have created. The source of the binding we have set to the view’s DataContext.

When the ProgressBarState property has changed, we handle this and call the VisualStateManager.GoToState method which will in turn trigger the animations to run, lovely.

 public partial class ProgressView : UserControl
    {

        public ProgressView()
        {
            InitializeComponent();

            Binding b = new Binding("ProgressBarState");
            b.Source = this.DataContext;
            this.SetBinding(ProgressBarStateProperty, b);
        }

        public ProgressBarState ProgressBarState
        {
            get { return (ProgressBarState)GetValue(ProgressBarStateProperty); }
            set { SetValue(ProgressBarStateProperty, value); }
        }

        public static readonly DependencyProperty ProgressBarStateProperty =
            DependencyProperty.Register("ProgressBarState", typeof(ProgressBarState), typeof(ProgressView), new PropertyMetadata(
        new PropertyChangedCallback(ProgressBarStatePropertyChanged)));

        static void ProgressBarStatePropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            VisualStateManager.GoToState((ProgressView)sender, e.NewValue.ToString(), true);
        }

    }

Now to the View Model. I’m using Caliburn Micro, but any old INotifyPropertyChanged implementation will do.

 ///
        /// Progress Bar Stage
        ///
        public ProgressBarState ProgressBarState
        {
            get { return _progressBarState; }
            set
            {
                _progressBarState = value;
                NotifyOfPropertyChange(() => ProgressBarState);
            }
        }

Simply have a property called ProgressBarState and set it’s value with a line of code such as

this.ProgressBarState = ProgressBarState.Shown;

I’ve used an enumeration to define the various Progress Bar States, i have two at this stage. I’m sure you can think of other scenarios where you might need more;)

    ///
    /// Represents progress bar states
    ///
    public enum ProgressBarState : int
    {
        Hidden = 0,
        Shown = 2
    }

Summary And that’s it! Note that at no time does the View know about the View Model or vice versa, all is right with the world. There are of course better and more elegant ways to achieve this with WPF and later versions of Silverlight, but this is the best way I’ve found in the current release of Windows Phone (v7.0).

Want to get started?

We would love to help with your next app or game, please do get in touch.