Infographics by vecteezy.com
I created some structures:
- Dispatching class
- UIDispatcher class
- InvokeOptions enumeration
First of all, and a basic thing, is to get UI Dispatcher. UI Dispatcher is a default WPF application dispatcher, co we can get it from static field like below.
This file contains 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
Dispatcher uiDispatcher = Application.Current.Dispatcher; |
But before we can use it, we should check if Application.Current isn't null. It can be null in special cases, e.g. when we run Visual Studio Unit Tests.
This file contains 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
Dispatcher uiDispatcher = null; | |
if (Application.Current != null) | |
{ | |
uiDispatcher = Application.Current.Dispatcher; | |
} |
Because sometimes we can get null instead of Dispatcher instance, I found iteresting solution in PRISM. We can create something similar to small bridge class, that will help to omit this issue. This class here will be called UIDispatcher.
This file contains 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
class UIDispatcher | |
{ | |
public void BeginInvoke(Delegate method, params object[] args) | |
{ | |
if ( Application.Current != null ) | |
{ | |
Application.Current.Dispatcher.BeginInvoke(method, DispatcherPriority.Normal, args); | |
} | |
} | |
} |
UIDispatcher is a simple class that have BeginInvoke method used to invoke some delegate in UI Thread, using UI Dispatcher if it is accessible. We can also pass arguments to this method.
Because I wanted to create universal invoking solution I decided to create similar invoke-thread-options to this in PRISM. So I created InvokeOptions enumeration.
This file contains 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 enum InvokeOptions | |
{ | |
PublisherThread, | |
UIThread, | |
BackgroundThread | |
} |
I ignored comments to clean code. PublisherThread option invoke method in the current thread, UIThread - in UI Thread, BackgroundThread - in background worker as Thread Pool Work Item (in my opinion better solution than background worker).
Finally We can see a target class:
This file contains 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 static class Dispatching | |
{ | |
static UIDispatcher _uiDispatcher; | |
static UIDispatcher UIDispatcher | |
{ | |
get | |
{ | |
if ( _uiDispatcher == null ) | |
{ | |
_uiDispatcher = new UIDispatcher(); | |
} | |
return _uiDispatcher; | |
} | |
} | |
public static void Invoke(Action method, InvokeOptions option) | |
{ | |
switch ( option ) | |
{ | |
case InvokeOptions.UIThread: | |
UIDispatcher.BeginInvoke(method); | |
break; | |
case InvokeOptions.BackgroundThread: | |
ThreadPool.QueueUserWorkItem(delegate(object o) | |
{ | |
method(); | |
}); | |
break; | |
case InvokeOptions.PublisherThread: | |
default: | |
method.Invoke(); | |
break; | |
} | |
} | |
public static void Invoke<TArg>(Action<TArg> method, TArg arg, InvokeOptions option) | |
{ | |
switch ( option ) | |
{ | |
case InvokeOptions.UIThread: | |
UIDispatcher.BeginInvoke(method, arg); | |
break; | |
case InvokeOptions.BackgroundThread: | |
ThreadPool.QueueUserWorkItem(delegate(object o) | |
{ | |
method(arg); | |
}); | |
break; | |
case InvokeOptions.PublisherThread: | |
default: | |
method.Invoke(arg); | |
break; | |
} | |
} | |
} |
What we can see here, there are two methods Invoke, used to invoke our methods or delegates in one of Thread options. I created two methods because I often use parameterless methods or delegates so the second was not needed. The second is helpful with others.
And how to use it, to have all clear.
This file contains 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 void ParameterlessMethod() | |
{ | |
// Doing some work | |
} | |
public void ParamMethod(EventArgs e) | |
{ | |
// bla bla other work | |
} | |
public void Invoker() | |
{ | |
// Invoke in current Thread | |
ParameterlessMethod(); | |
ParamMethod(EventArgs.Empty); | |
Dispatching.Invoke(ParameterlessMethod, InvokeOptions.PublisherThread); | |
Dispatching.Invoke<eventargs>(ParamMethod, EventArgs.Empty, InvokeOptions.PublisherThread); | |
// Invoke in current UI Thread | |
Dispatching.Invoke(ParameterlessMethod, InvokeOptions.UIThread); | |
Dispatching.Invoke<eventargs>(ParamMethod, EventArgs.Empty, InvokeOptions.UIThread); | |
// Invoke in background | |
Dispatching.Invoke(ParameterlessMethod, InvokeOptions.BackgroundThread); | |
Dispatching.Invoke<eventargs>(ParamMethod, EventArgs.Empty, InvokeOptions.BackgroundThread); | |
} |
All of code presented here can be download in one file in Downloads section below.
Hope this will be helpful.
Comments
Post a Comment