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.
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
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;
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;
}
}
public int Selection
{
get
{
return selection;
}
set
{
if (value != selection && value >= 0 && value < elements.Length)
{
OnFadeAnimation_Completed(this, null);
if (fadeAnimation == null)
{
elements[selection].Visibility = Visibility.Hidden;
elements[value].Visibility = Visibility.Visible;
}
else if (value < selection)
{
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)
{
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;
elementToHide.BeginAnimation(UIElement.OpacityProperty, null);
elementToHide.Opacity = 1.0;
elementToHide = null;
}
}
}
I hope that you find this class useful in your applications!