Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WPF

Switch Between a Set of UI Elements with Fade

0.00/5 (No votes)
11 Apr 2015CPOL1 min read 8.9K  
A helper class for tabs-style navigation in WPF, and an example of how to animate the Opacity property.

Introduction

I develop WPF rich client applications for CNC machine control and there is often a need for tabs-style navigation. Machine operators hate it when tabs change rows when selected because it makes them have to search for the proper tab instead of being able to memorize their locations. I therefore roll my own tabs-style navigation using a wrap panel of buttons styled to look like tabs. I create a set of grids or user controls stacked up in the content area with only one of them shown at a time.

I've created a helper class that encapsulates the function of hiding the current selection and making the new selection visible. The class also supports optional fade animations.

Using the class in your program is as simple as instantiating it and then setting the Selection property when the user clicks one of your "tab" buttons. The array of elements provided to the constructor must be in Z-order, with the lowest element at index zero. The initial index may also be specified along with the fade interval in milliseconds. Set the interval to zero for instant switching.

C#
tabsSwitcher = new Switcher(new UIElement[] { gridAutoTab, gridMdiTab, gridManualTab }, 0, 200);
tabsSwitcher.Selection = 1;

This little class should be especially interesting to folks who are trying to get Opacity animations to work correctly in WPF. Note that the class takes relative Z-order into account when animating the transition between two elements.

The Code

C#
using System;
using System.Windows;
using System.Windows.Media.Animation;

public class Switcher
{
    private UIElement[] elements;
    private int selection;
    private DoubleAnimation fadeAnimation = null;
    private UIElement elementToHide = null;

    /// <summary>Switches Visibility to one of an array of 
    /// <see cref="UIElement"/>.</summary>
    /// <param name="elements">The array of elements.</param>
    /// <param name="selection">The element that will be initially visible.</param>
    /// <param name="milliseconds">Fade interval for transitions. 
    /// Set to zero for instant switch.</param>
    /// <remarks>Array of elements must be in Z-order, with the lowest element at index zero.</remarks>
    public Switcher(UIElement[] elements, int selection = 0, int milliseconds = 200)
    {
        this.elements = elements;
        this.selection = selection;

        foreach (UIElement element in elements)
            element.Visibility = Visibility.Hidden;

        if (selection >= 0 && selection < elements.Length)
            elements[selection].Visibility = Visibility.Visible;

        if (milliseconds > 0)
        {
            fadeAnimation = new DoubleAnimation();
            fadeAnimation.Duration = TimeSpan.FromMilliseconds(milliseconds);
            fadeAnimation.Completed += OnFadeAnimation_Completed;
        }
    }

    /// <summary>Switches Visibility to another element in the array.</summary>
    public int Selection
    {
        get
        {
            return selection;
        }
        set
        {
            if (value != selection && value >= 0 && value < elements.Length)
            {
                OnFadeAnimation_Completed(this, null);  // in case user switches during an animation

                if (fadeAnimation == null)  // instant transition
                {
                    elements[selection].Visibility = Visibility.Hidden;
                    elements[value].Visibility = Visibility.Visible;
                }
                else if (value < selection)  // higher-to-lower transition
                {
                    // Show lower element (hidden behind upper), fade out higher element then hide it.
                    elements[value].Opacity = 1.0;
                    elements[value].Visibility = Visibility.Visible;
                    elementToHide = elements[selection];
                    fadeAnimation.From = 1.0;
                    fadeAnimation.To = 0.0;
                    elements[selection].BeginAnimation(UIElement.OpacityProperty, fadeAnimation);
                }
                else if (value > selection)  // lower-to-higher transition
                {
                    // Zero higher element opacity and show it, then fade it in and hide lower element.
                    elements[value].Opacity = 0.0;
                    elements[value].Visibility = Visibility.Visible;
                    elementToHide = elements[selection];
                    fadeAnimation.From = 0.0;
                    fadeAnimation.To = 1.0;
                    elements[value].BeginAnimation(UIElement.OpacityProperty, fadeAnimation);
                }

                selection = value;
            }
        }
    }

    private void OnFadeAnimation_Completed(object sender, EventArgs e)
    {
        if (elementToHide != null)
        {
            elementToHide.Visibility = Visibility.Hidden;
            // disconnect the animation so that Opacity can be set:
            elementToHide.BeginAnimation(UIElement.OpacityProperty, null);
            elementToHide.Opacity = 1.0;
            elementToHide = null;
        }
    }
}

I hope that you find this class useful in your applications!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)