using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Shapes;
using System.Windows.Threading;
namespace Microsoft.Windows.Controls
{
///
/// A control to provide a visual indicator when an application is busy.
///
[TemplateVisualState(Name = VisualStates.StateIdle, GroupName = VisualStates.GroupBusyStatus)]
[TemplateVisualState(Name = VisualStates.StateBusy, GroupName = VisualStates.GroupBusyStatus)]
[TemplateVisualState(Name = VisualStates.StateVisible, GroupName = VisualStates.GroupVisibility)]
[TemplateVisualState(Name = VisualStates.StateHidden, GroupName = VisualStates.GroupVisibility)]
[StyleTypedProperty(Property = "OverlayStyle", StyleTargetType = typeof(Rectangle))]
[StyleTypedProperty(Property = "ProgressBarStyle", StyleTargetType = typeof(ProgressBar))]
public class BusyIndicator : ContentControl
{
#region Private Members
///
/// Timer used to delay the initial display and avoid flickering.
///
private DispatcherTimer _displayAfterTimer = new DispatcherTimer();
#endregion //Private Members
#region Constructors
static BusyIndicator()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(BusyIndicator), new FrameworkPropertyMetadata(typeof(BusyIndicator)));
}
public BusyIndicator()
{
_displayAfterTimer.Tick += DisplayAfterTimerElapsed;
}
#endregion //Constructors
#region Base Class Overrides
///
/// Overrides the OnApplyTemplate method.
///
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
ChangeVisualState(false);
}
#endregion //Base Class Overrides
#region Properties
///
/// Gets or sets a value indicating whether the BusyContent is visible.
///
protected bool IsContentVisible { get; set; }
#endregion //Properties
#region Dependency Properties
#region IsBusy
///
/// Identifies the IsBusy dependency property.
///
public static readonly DependencyProperty IsBusyProperty = DependencyProperty.Register(
"IsBusy",
typeof(bool),
typeof(BusyIndicator),
new PropertyMetadata(false, new PropertyChangedCallback(OnIsBusyChanged)));
///
/// Gets or sets a value indicating whether the busy indicator should show.
///
public bool IsBusy
{
get { return (bool)GetValue(IsBusyProperty); }
set { SetValue(IsBusyProperty, value); }
}
///
/// IsBusyProperty property changed handler.
///
/// BusyIndicator that changed its IsBusy.
/// Event arguments.
private static void OnIsBusyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((BusyIndicator)d).OnIsBusyChanged(e);
}
///
/// IsBusyProperty property changed handler.
///
/// Event arguments.
protected virtual void OnIsBusyChanged(DependencyPropertyChangedEventArgs e)
{
if (IsBusy)
{
if (DisplayAfter.Equals(TimeSpan.Zero))
{
// Go visible now
IsContentVisible = true;
}
else
{
// Set a timer to go visible
_displayAfterTimer.Interval = DisplayAfter;
_displayAfterTimer.Start();
}
}
else
{
// No longer visible
_displayAfterTimer.Stop();
IsContentVisible = false;
}
ChangeVisualState(true);
}
#endregion //IsBusy
#region Busy Content
///
/// Identifies the BusyContent dependency property.
///
public static readonly DependencyProperty BusyContentProperty = DependencyProperty.Register(
"BusyContent",
typeof(object),
typeof(BusyIndicator),
new PropertyMetadata(null));
///
/// Gets or sets a value indicating the busy content to display to the user.
///
public object BusyContent
{
get { return (object)GetValue(BusyContentProperty); }
set { SetValue(BusyContentProperty, value); }
}
#endregion //Busy Content
#region Busy Content Template
///
/// Identifies the BusyTemplate dependency property.
///
public static readonly DependencyProperty BusyContentTemplateProperty = DependencyProperty.Register(
"BusyContentTemplate",
typeof(DataTemplate),
typeof(BusyIndicator),
new PropertyMetadata(null));
///
/// Gets or sets a value indicating the template to use for displaying the busy content to the user.
///
public DataTemplate BusyContentTemplate
{
get { return (DataTemplate)GetValue(BusyContentTemplateProperty); }
set { SetValue(BusyContentTemplateProperty, value); }
}
#endregion //Busy Content Template
#region Display After
///
/// Identifies the DisplayAfter dependency property.
///
public static readonly DependencyProperty DisplayAfterProperty = DependencyProperty.Register(
"DisplayAfter",
typeof(TimeSpan),
typeof(BusyIndicator),
new PropertyMetadata(TimeSpan.FromSeconds(0.1)));
///
/// Gets or sets a value indicating how long to delay before displaying the busy content.
///
public TimeSpan DisplayAfter
{
get { return (TimeSpan)GetValue(DisplayAfterProperty); }
set { SetValue(DisplayAfterProperty, value); }
}
#endregion //Display After
#region Overlay Style
///
/// Identifies the OverlayStyle dependency property.
///
public static readonly DependencyProperty OverlayStyleProperty = DependencyProperty.Register(
"OverlayStyle",
typeof(Style),
typeof(BusyIndicator),
new PropertyMetadata(null));
///
/// Gets or sets a value indicating the style to use for the overlay.
///
public Style OverlayStyle
{
get { return (Style)GetValue(OverlayStyleProperty); }
set { SetValue(OverlayStyleProperty, value); }
}
#endregion //Overlay Style
#region ProgressBar Style
///
/// Identifies the ProgressBarStyle dependency property.
///
public static readonly DependencyProperty ProgressBarStyleProperty = DependencyProperty.Register(
"ProgressBarStyle",
typeof(Style),
typeof(BusyIndicator),
new PropertyMetadata(null));
///
/// Gets or sets a value indicating the style to use for the progress bar.
///
public Style ProgressBarStyle
{
get { return (Style)GetValue(ProgressBarStyleProperty); }
set { SetValue(ProgressBarStyleProperty, value); }
}
#endregion //ProgressBar Style
#endregion //Dependency Properties
#region Methods
///
/// Handler for the DisplayAfterTimer.
///
/// Event sender.
/// Event arguments.
private void DisplayAfterTimerElapsed(object sender, EventArgs e)
{
_displayAfterTimer.Stop();
IsContentVisible = true;
ChangeVisualState(true);
}
///
/// Changes the control's visual state(s).
///
/// True if state transitions should be used.
protected virtual void ChangeVisualState(bool useTransitions)
{
VisualStateManager.GoToState(this, IsBusy ? VisualStates.StateBusy : VisualStates.StateIdle, useTransitions);
VisualStateManager.GoToState(this, IsContentVisible ? VisualStates.StateVisible : VisualStates.StateHidden, useTransitions);
}
#endregion //Methods
}
}