1. namespace GalaSoft.MvvmLight.Messaging
  2. {
  3.     using System;
  4.  
  5.     /// <summary>
  6.     /// Use this class to send a message when the busy state of an application changes.
  7.     /// </summary>
  8.     public class BusyMessage : MessageBase
  9.     {
  10.         /// <summary>
  11.         /// Initializes a new instance of the <see cref="BusyMessage"/> class.
  12.         /// </summary>
  13.         /// <param name="isBusy"><b>true</b> if the application is busy; otherwise, <b>false</b>.</param>
  14.         /// <param name="userState">Optional. User state information to include with the message.</param>
  15.         public BusyMessage(bool isBusy, object userState)
  16.             : this(isBusy, userState, null)
  17.         {
  18.         }
  19.  
  20.         /// <summary>
  21.         /// Initializes a new instance of the <see cref="BusyMessage"/> class.
  22.         /// </summary>
  23.         /// <param name="isBusy"><b>true</b> if the application is busy; otherwise, <b>false</b>.</param>
  24.         /// <param name="userState">Optional. User state information to include with the message.</param>
  25.         /// <param name="sender">Optional. The message's original sender.</param>
  26.         public BusyMessage(bool isBusy, object userState, object sender)
  27.             : base(sender)
  28.         {
  29.             this.IsBusy = isBusy;
  30.             this.UserState = userState;
  31.         }
  32.  
  33.         /// <summary>
  34.         /// Gets a value indicating whether the application is currently in a busy state.
  35.         /// </summary>
  36.         public bool IsBusy { get; private set; }
  37.        
  38.         /// <summary>
  39.         /// Gets user state information to include with the message.
  40.         /// </summary>
  41.         public object UserState { get; private set; }
  42.     }
  43.  
  44. }
  45.  
  46. namespace GalaSoft.MvvmLight.Threading
  47. {
  48.     using System;
  49.     using System.Threading;
  50.     using GalaSoft.MvvmLight.Messaging;
  51.  
  52.     /// <summary>
  53.     /// Provides a thread-safe controller for managing the busy state of the application.
  54.     /// </summary>
  55.     public class BusyController : GalaSoft.MvvmLight.ObservableObject
  56.     {
  57.         private readonly object SyncRoot = new object();
  58.         private int count;
  59.  
  60.         /// <summary>
  61.         /// Initializes static members of the <see cref="BusyController"/> class.
  62.         /// </summary>
  63.         static BusyController()
  64.         {
  65.             _default = new BusyController();
  66.         }
  67.  
  68.         /// <summary>
  69.         /// Initializes a new instance of the <see cref="BusyController"/> class.
  70.         /// </summary>
  71.         public BusyController()
  72.             : this(Messenger.Default)
  73.         {
  74.         }
  75.  
  76.         /// <summary>
  77.         /// Initializes a new instance of the <see cref="BusyController"/> class.
  78.         /// </summary>
  79.         /// <param name="messenger">Optional. An <see cref="IMessenger"/> which will be used to send messages.</param>
  80.         public BusyController(IMessenger messenger)
  81.         {
  82.             this.MessengerInstance = messenger;
  83.         }
  84.  
  85.         private static BusyController _default;
  86.  
  87.         /// <summary>
  88.         /// Gets the default busy controller instance.
  89.         /// </summary>
  90.         public static BusyController Default
  91.         {
  92.             get
  93.             {
  94.                 return _default;
  95.             }
  96.         }
  97.  
  98.         private bool _isBusy;
  99.  
  100.         /// <summary>
  101.         /// Gets a value indicating whether the controller is currently in the busy state.
  102.         /// </summary>
  103.         public bool IsBusy
  104.         {
  105.             get
  106.             {
  107.                 return this._isBusy;
  108.             }
  109.  
  110.             private set
  111.             {
  112.                 if (this._isBusy != value)
  113.                 {
  114.                     this._isBusy = value;
  115.                     this.RaisePropertyChanged(() => this.IsBusy);
  116.                 }
  117.             }
  118.         }
  119.  
  120.         private IMessenger _messengerInstance;
  121.  
  122.         /// <summary>
  123.         /// Gets the messenger instance used by the controller.
  124.         /// </summary>
  125.         protected IMessenger MessengerInstance
  126.         {
  127.             get
  128.             {
  129.                 return this._messengerInstance;
  130.             }
  131.  
  132.             set
  133.             {
  134.                 if (this._messengerInstance != value)
  135.                 {
  136.                     this._messengerInstance = value;
  137.                     this.RaisePropertyChanged(() => this.MessengerInstance);
  138.                 }
  139.             }
  140.         }
  141.  
  142.         /// <summary>
  143.         /// Resets the controller.
  144.         /// </summary>
  145.         public void Reset()
  146.         {
  147.             lock (this.SyncRoot)
  148.             {
  149.                 this.IsBusy = false;
  150.                 this.count = 0;
  151.  
  152.                 if (this.MessengerInstance != null)
  153.                 {
  154.                     // Send the message indicating that the controller is no longer busy.
  155.                     this.MessengerInstance.Send<BusyMessage>(new BusyMessage(this.IsBusy, null));
  156.                 }
  157.             }
  158.         }
  159.  
  160.         /// <summary>
  161.         /// Sends the message.
  162.         /// </summary>
  163.         /// <param name="value"><b>true</b> if the application is busy; otherwise, <b>false</b> when the application is no longer busy.</param>        
  164.         public void SendMessage(bool value)
  165.         {
  166.             this.SendMessage(value, null);
  167.         }
  168.  
  169.         /// <summary>
  170.         /// Sends the message.
  171.         /// </summary>
  172.         /// <param name="value"><b>true</b> if the application is busy; otherwise, <b>false</b> when the application is no longer busy.</param>
  173.         /// <param name="state">Optional. User state data to include with the message if the controller transitions between busy states.</param>
  174.         public void SendMessage(bool value, object userState)
  175.         {
  176.             lock (this.SyncRoot)
  177.             {
  178.                 bool send = false;
  179.  
  180.                 if (value)
  181.                 {
  182.                     Interlocked.Increment(ref this.count);
  183.  
  184.                     if (this.count == 1)
  185.                     {
  186.                         this.IsBusy = true;
  187.  
  188.                         // The controller is now busy, send the message.
  189.                         send = true;
  190.                     }
  191.                 }
  192.                 else
  193.                 {
  194.                     if (this.count > 0)
  195.                     {
  196.                         Interlocked.Decrement(ref this.count);
  197.  
  198.                         if (this.count == 0)
  199.                         {
  200.                             this.IsBusy = false;
  201.  
  202.                             // The controller is no longer busy, send the message.
  203.                             send = true;
  204.                         }
  205.                     }
  206.                 }
  207.  
  208.                 if (send && this.MessengerInstance != null)
  209.                 {
  210.                     this.MessengerInstance.Send<BusyMessage>(new BusyMessage(this.IsBusy, userState, this));
  211.                 }
  212.             }            
  213.         }
  214.     }
  215. }