Last active
January 13, 2017 02:13
-
-
Save heiswayi/e7b722e139918565919851829377e22b to your computer and use it in GitHub Desktop.
C# SmartDispatcher class by Jeff Wilcox for WPF MVVM
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public App() | |
{ | |
this.Startup += this.Application_Startup; | |
this.Exit += this.Application_Exit; | |
this.UnhandledException += this.Application_UnhandledException; | |
SmartDispatcher.Initialize(Deployment.Current.Dispatcher); | |
InitializeComponent(); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// (c) Copyright Microsoft Corporation. | |
// This source is subject to the Microsoft Public License (Ms-PL). | |
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details. | |
// All other rights reserved. | |
using System; | |
using System.Collections.Generic; | |
using System.Windows.Threading; | |
namespace System.ComponentModel | |
{ | |
/// <summary> | |
/// A base class for data objects that implement the property changed | |
/// interface, offering data binding and change notifications. | |
/// </summary> | |
public class PropertyChangedBase : INotifyPropertyChanged | |
{ | |
/// <summary> | |
/// A static set of argument instances, one per property name. | |
/// </summary> | |
private static Dictionary<string, PropertyChangedEventArgs> _argumentInstances = new Dictionary<string, PropertyChangedEventArgs>(); | |
/// <summary> | |
/// The property changed event. | |
/// </summary> | |
public event PropertyChangedEventHandler PropertyChanged; | |
/// <summary> | |
/// Notify any listeners that the property value has changed. | |
/// </summary> | |
/// <param name="propertyName">The property name.</param> | |
protected void NotifyPropertyChanged(string propertyName) | |
{ | |
PropertyChangedEventHandler handler = PropertyChanged; | |
if (handler != null) | |
{ | |
PropertyChangedEventArgs args; | |
if (!_argumentInstances.TryGetValue(propertyName, out args)) | |
{ | |
args = new PropertyChangedEventArgs(propertyName); | |
_argumentInstances[propertyName] = args; | |
} | |
// Fire the change event. The smart dispatcher will directly | |
// invoke the handler if this change happened on the UI thread, | |
// otherwise it is sent to the proper dispatcher. | |
SmartDispatcher.BeginInvoke(delegate | |
{ | |
handler(this, args); | |
}); | |
} | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// (c) Copyright Microsoft Corporation. | |
// This source is subject to the Microsoft Public License (Ms-PL). | |
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details. | |
// All other rights reserved. | |
using System.ComponentModel; | |
namespace System.Windows.Threading | |
{ | |
/// <summary> | |
/// A smart dispatcher system for routing actions to the user interface | |
/// thread. | |
/// </summary> | |
public static class SmartDispatcher | |
{ | |
/// <summary> | |
/// A single Dispatcher instance to marshall actions to the user | |
/// interface thread. | |
/// </summary> | |
private static Dispatcher _instance; | |
/// <summary> | |
/// Backing field for a value indicating whether this is a design-time | |
/// environment. | |
/// </summary> | |
private static bool? _designer; | |
/// <summary> | |
/// Requires an instance and attempts to find a Dispatcher if one has | |
/// not yet been set. | |
/// </summary> | |
private static void RequireInstance() | |
{ | |
if (_designer == null) | |
{ | |
_designer = DesignerProperties.IsInDesignTool; | |
} | |
// Design-time is more of a no-op, won't be able to resolve the | |
// dispatcher if it isn't already set in these situations. | |
if (_designer == true) | |
{ | |
return; | |
} | |
// Attempt to use the RootVisual of the plugin to retrieve a | |
// dispatcher instance. This call will only succeed if the current | |
// thread is the UI thread. | |
try | |
{ | |
_instance = Application.Current.RootVisual.Dispatcher; | |
} | |
catch (Exception e) | |
{ | |
throw new InvalidOperationException("The first time SmartDispatcher is used must be from a user interface thread. Consider having the application call Initialize, with or without an instance.", e); | |
} | |
if (_instance == null) | |
{ | |
throw new InvalidOperationException("Unable to find a suitable Dispatcher instance."); | |
} | |
} | |
/// <summary> | |
/// Initializes the SmartDispatcher system, attempting to use the | |
/// RootVisual of the plugin to retrieve a Dispatcher instance. | |
/// </summary> | |
public static void Initialize() | |
{ | |
if (_instance == null) | |
{ | |
RequireInstance(); | |
} | |
} | |
/// <summary> | |
/// Initializes the SmartDispatcher system with the dispatcher | |
/// instance. | |
/// </summary> | |
/// <param name="dispatcher">The dispatcher instance.</param> | |
public static void Initialize(Dispatcher dispatcher) | |
{ | |
if (dispatcher == null) | |
{ | |
throw new ArgumentNullException("dispatcher"); | |
} | |
_instance = dispatcher; | |
if (_designer == null) | |
{ | |
_designer = DesignerProperties.IsInDesignTool; | |
} | |
} | |
/// <summary> | |
/// | |
/// </summary> | |
/// <returns></returns> | |
public static bool CheckAccess() | |
{ | |
if (_instance == null) | |
{ | |
RequireInstance(); | |
} | |
return _instance.CheckAccess(); | |
} | |
/// <summary> | |
/// Executes the specified delegate asynchronously on the user interface | |
/// thread. If the current thread is the user interface thread, the | |
/// dispatcher if not used and the operation happens immediately. | |
/// </summary> | |
/// <param name="a">A delegate to a method that takes no arguments and | |
/// does not return a value, which is either pushed onto the Dispatcher | |
/// event queue or immediately run, depending on the current thread.</param> | |
public static void BeginInvoke(Action a) | |
{ | |
if (_instance == null) | |
{ | |
RequireInstance(); | |
} | |
// If the current thread is the user interface thread, skip the | |
// dispatcher and directly invoke the Action. | |
if (_instance.CheckAccess() || _designer == true) | |
{ | |
a(); | |
} | |
else | |
{ | |
_instance.BeginInvoke(a); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment