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 } }