/************************************************************************************* Extended WPF Toolkit Copyright (C) 2007-2013 Xceed Software Inc. This program is provided to you under the terms of the Microsoft Public License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license For more features, controls, and fast professional support, pick up the Plus Edition at http://xceed.com/wpf_toolkit Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids ***********************************************************************************/ using System; using System.Windows; using System.Windows.Controls; using System.Windows.Shapes; using System.Windows.Threading; namespace Xceed.Wpf.Toolkit { /// /// 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; if( this.FocusAfterBusy != null ) { this.FocusAfterBusy.Dispatcher.BeginInvoke( DispatcherPriority.Input, new Action( () => { this.FocusAfterBusy.Focus(); } ) ); } } 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 FocusAfterBusy /// /// Identifies the FocusAfterBusy dependency property. /// public static readonly DependencyProperty FocusAfterBusyProperty = DependencyProperty.Register( "FocusAfterBusy", typeof( Control ), typeof( BusyIndicator ), new PropertyMetadata( null ) ); /// /// Gets or sets a Control that should get focus when the busy indicator disapears. /// public Control FocusAfterBusy { get { return ( Control )GetValue( FocusAfterBusyProperty ); } set { SetValue( FocusAfterBusyProperty, value ); } } #endregion //FocusAfterBusy #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 } }