Animating Switching Themes

Feb 10, 2009 at 8:38 PM
A while ago I had the idea of using an animated transition when the user switches themes. I decided to try it out using the themes in this library, originally I was using an Image in an Adorner and animating the opacity mask, this worked ok. I then added support for the transition effects available at http://www.codeplex.com/wpffx this gave better results with much less code as these effects removed the need for adorners or any other elements.

If you want to try it out here are some instructions.
1. Download and compile the "Windows Presentation Foundation Pixel Shader Effects Library" from http://www.codeplex.com/wpffx
2. Reference TransitionEffects.dll in the WPF.Themes project.
3. You can then transition on theme switching with something along the lines of the code below.
4. Try out the demo project.

Check the requirements section of the Shader Effect Library as it has some dependencies. The example code just cycles through the different effects and doesn't change any shader specific settings, you'll probably want to alter it.

In ThemeManager.cs replace the exisiting ApplyTheme(ContentControl,) method.
public static void ApplyTheme(this ContentControl control, string theme)
{
    ResourceDictionary dictionary = ThemeManager.GetThemeResourceDictionary(theme);

    if (dictionary != null)
    {
        if(control.Resources.MergedDictionaries.Count > 0)
            Transition(control);
        control.Resources.MergedDictionaries.Clear();
        control.Resources.MergedDictionaries.Add(dictionary);
    }
}
private static TransitionEffect[] effects;
private static int effectIndex = 0;
private static void Transition(ContentControl control)
{
    var content = control.Content as FrameworkElement;
    content = content ?? control;

    var image = new RenderTargetBitmap((int)content.ActualWidth, (int)content.ActualHeight, 96, 96, PixelFormats.Pbgra32);
    image.Render(control);

    if (effects == null)
    {
        effects = (from e in typeof(TransitionEffect).Assembly.GetTypes()
                   where !e.IsAbstract
                   select (TransitionEffect)Activator.CreateInstance(e)).ToArray();
    }
    var effect = effects[effectIndex];
    effectIndex = (effectIndex + 1) % effects.Length;
    effect.OldImage = new ImageBrush(image);

    control.Effect = effect;
    
    var anim = new DoubleAnimation(0, 1, TimeSpan.FromSeconds(2)) { AccelerationRatio = 0.5};
    anim.Completed += (s, e) => control.Effect = null;
    effect.BeginAnimation(TransitionEffect.ProgressProperty, anim);
}