While producing my new, pretty WMP remote control, I wanted to have clever navigation animations similar to those found in FrontRow. The example I used (/backRow) accomplished this in a pretty ugly way. All of the controls were set up off-screen and flown on-screen according to some animation trigger. This worked, but it made it impossible to edit the contents of the pages with Expression Blend or the Visual Studio editor. So, I decided to use page navigation instead.
The trick was to figure out how to change the look and feel of the page navigation. By default, windows just appear over the old windows with no magical transitional WPF-ness. In comes the AnimationBehaviors Project on CodePlex. This clever little project allows me to control how a window is loaded and unloaded. So, in our case, we can define a page, the contents of which are an AnimationBehaviorHost, and set the AnimationBehaviorHost.LoadedBehavior to LoadedBehavior.SlideInFromRight.
That worked great, except that everything slide in from the right even if we were navigating backwards! It just didn't look right. What would be great is if the LoadedBehavior dynamically changed based on the direction of navigation. Sounds like a great used of Binding.
The first thing to do was to create a place to store the current animation behavior:
public class NavigationAnimation : INotifyPropertyChanged { // Singleton class private NavigationAnimation() { } public enum NavigationDirection { Forward, Backward }; private static NavigationAnimation _instance = new NavigationAnimation(); public static NavigationAnimation Instance { get { return NavigationAnimation._instance; } set { NavigationAnimation._instance = value; } } public static void SetNavigationDirection(NavigationDirection direction) { if(NavigationDirection.Forward==direction) { Instance.AnimationBehavior = LoadedBehavior.SlideInFromRight; } else { Instance.AnimationBehavior = LoadedBehavior.SlideInFromLeft; } } private LoadedBehavior _animationBehavior = LoadedBehavior.SlideInFromRight; public LoadedBehavior AnimationBehavior { get { return _animationBehavior; } set { _animationBehavior = value; OnPropertyChanged("AnimationBehavior"); } } private void OnPropertyChanged(string propertyName) { if (null != PropertyChanged) { PropertyChangedEventArgs e = new PropertyChangedEventArgs(propertyName); PropertyChanged(this,e); } } public event PropertyChangedEventHandler PropertyChanged; }
Next, we need to change the animation behavior based on our navigation state so we add an event handler to the NavigationFrame's Navigating event that looks something like this:
private void OnNavigating(object sender, NavigatingCancelEventArgs e) { if (e.NavigationMode == NavigationMode.Back) { NavigationAnimation.SetNavigationDirection(NavigationAnimation.NavigationDirection.Backward); } else { NavigationAnimation.SetNavigationDirection(NavigationAnimation.NavigationDirection.Forward); } }
Finally, we bind our AnimationBehaviorHost.LoadedBehavior to our current animation behavior.
That's it! Navigating forward slides the windows in from the right, while navigating backward slides the windows in from the left. I may finally be getting the hang of this stuff!
Disclaimer The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.