Introduction

WPF has very powerful animation capabilities, but in some cases, these are quite hard to use in combination with data driven content. One example is when a ContentControl is dynamically rendering a View based on a bound object in its ViewModel.

This article shows a solution where a standard ContentControl is enhanced to animate the transitions between content while still maintaining its familiar functionality and behavior.

The AnimatedContentControl

The control provided in the sample is a standalone control inheriting from ContentControl which will apply a right-to-left fly-out animation whenever it detects that its content has changed. It doesn't matter if content comes from databinding, from code-behind, or from XAML. In fact, apart from the animation, it behaves just like a normal ContentControl.

The control is created as a "Custom Control", which differs from a User control in that it:

can inherit from any WPF control, instead of just UserControl

doesn't have a backing .xaml file and thus cannot make hard assumptions about its visual tree (it does have a default style though, which is what we'll use in this article)

It's outside the scope of this article to discuss the differences between these two approaches, but since we wanted to create a ContentControl, we had to go with the "Custom Control" approach.

To handle the animation, the AnimatedContentControl needs something to temporarily draw the old content to. And, in the default style for the control, we add a rectangle for this purpose. The rectangle is the same size as the content, and occupies the same space in the layout. We will control the positioning and visibility from code later, of course.

Notice the naming used for the controls we need to use in our code. This follows the naming convention for custom controls, and gives us a way to get hold of these controls in our C# code. This is discussed more in detail in this CodeProject article, but in short, we can use the GetName method after the template has been applied to get references to the controls.

///<summary>/// This gets called when the template has been applied and we have our visual tree
///</summary>publicoverridevoid OnApplyTemplate()
{
m_paintArea = Template.FindName("PART_PaintArea", this) as Shape;
m_mainContent = Template.FindName("PART_MainContent", this) as ContentPresenter;
base.OnApplyTemplate();
}

Reacting to content changes

The base class provides an overload called OnContentChanged that we can use to perform some work when the content has changed. One thing to note is that when this is called, the actual property has changed (so if we look at this.Content, it would be equal to the newContent parameter), but the visual appearance has not yet been updated. We exploit this by capturing the current visual appearance and paint it on top of our temporary rectangle.

In the above method, we create two new TranslateTransforms. These are responsible for moving the content to the left, side by side:

The animation for our temporary rectangle starts from the location where the original content was shown, and will be moved left until it is completely outside the visible area of the control.

The animation for our new content, which is applied to the ContentPresenter (the one holding the new visual appearance by the time the animation starts), will start off screen to the right, and moves in until it occupies its final location.

To make the transition feel more alive, we're using an easing function with a BackEase algorithm. This will make the animated content travel slightly too far and then bounce back to its resting place. The code used to create the animations is wrapped in a simple method:

DataBinding

The downloadable source code shows how this control is used in an MVVM (Model-View-ViewModel) architecture, with content being changed from ViewModels, which is completely unaware of the animations done in the View layer.

The ViewModel for the main window, MainWindowViewModel, contains a property called Content and a command called ChangeContentCommand. These are bound from the MainWindow like so:

When the command is executed in the ViewModel, it just sets its Content property to a new instance of a MyContentViewModel. The property notification system will then notify our control of the new content, and it will in turn trigger the animation.

Points of Interest

The animations in this example are very simple. It's only animating a translation of the X-axis and, thanks to the easing function, still provides a visually appealing effect. That said though, a visual designer could quite easily enhance this to provide an even richer experience, and the good thing is that the programming interface towards the control doesn't change at all.

Share

About the Author

My name is Isak Savo and I work as a Research Engineer at ABB Corporate Research in Västerås, Sweden. My work is focused around user experience which includes a lot of prototyping of new solutions for user interfaces and user interaction.

While I have a background in C programming in a Linux environment, my daily work is mostly spent in Windows using C# and WPF.