Here is a good way to use extension method in a multi threaded context. Everybody knows that when you try to update UI from any other thread than the UI you get an “InvalidOperationException” with message “The calling thread cannot access this object because a different thread owns it.”. Look at the following sample:
Let say somewhere in your code you have this
private void Button_Click(object sender, RoutedEventArgs e)
{
// ...
ThreadPool.QueueUserWorkItem(DoWork, this);
// ...
}
If you implement DoWork Like this…
private static void DoWork(object state)
{
Window1 win = (Window1) state;
for (int i = 0; i < 100; i++)
{
// do some work
win.progress1.Value = i;
}
win.progress1.Value = 100;
}
…you will be in trouble.
Because you can’t update UI from a thread other than the UI one you will get the InvalidOperationException as stated before.
The solution is to use the Dispatcher object. As from microsoft documentation:
Only the thread that the Dispatcher was created on may access the DispatcherObject directly. To access a DispatcherObject from a thread other than the thread theDispatcherObject was created on, call Invoke or BeginInvoke on the Dispatcher the DispatcherObject is associated with.
Subclasses of DispatcherObject that need to enforce thread safety can do so by calling VerifyAccess on all public methods. This guarantees the calling thread is the thread that theDispatcherObject was created on.
So our previous sample should look like this:
private static void DoWork(object state)
{
Window1 win = (Window1) state;
for (int i = 0; i < 100; i++)
{
// do some work
win.Dispatcher.Invoke(new Action<ProgressBar, int>((p, v) => p.Value = v), win.progress1, i);
}
win.Dispatcher.Invoke(new Action<ProgressBar>(p => p.Value = 100), win.progress1);
}
This is a little more work but not it works. Because we don’t want to call the Dispatcher object when it’s not needed we sould do this:
private static void DoWork(object state)
{
Window1 win = (Window1) state;
for (int i = 0; i < 100; i++)
{
// do some work
if (win.Dispatcher.CheckAccess())
// We can call on the current thread
win.progress1.Value = i;
else
// we need to call Invoke
win.Dispatcher.Invoke(new Action<ProgressBar, int>((p, v) => p.Value = v), win.progress1, i);
}
if (win.Dispatcher.CheckAccess())
// We can call on the current thread
win.progress1.Value = 100;
else
// we need to call Invoke
win.Dispatcher.Invoke(new Action<ProgressBar>(p => p.Value = 100), win.progress1);
}
Ouch! This is a lot more work. We cannot do that every time. That’s when extensions method comes handy. We can replace this whole process of choosing the right implementation with a single extension method. It will make our code more readable and more managable.
He is the whole extension class with all possible overload for a method called Dispatch. This method will dispatch the process only if needed:
public static class DispatcherExtensions
{
public static TResult Dispatch<TResult>(this DispatcherObject source, Func<TResult> func)
{
if (source.Dispatcher.CheckAccess())
return func();
return (TResult) source.Dispatcher.Invoke(func);
}
public static TResult Dispatch<T, TResult>(this T source, Func<T, TResult> func) where T : DispatcherObject
{
if (source.Dispatcher.CheckAccess())
return func(source);
return (TResult)source.Dispatcher.Invoke(func, source);
}
public static TResult Dispatch<TSource, T, TResult>(this TSource source, Func<TSource, T, TResult> func, T param1) where TSource : DispatcherObject
{
if (source.Dispatcher.CheckAccess())
return func(source, param1);
return (TResult)source.Dispatcher.Invoke(func, source, param1);
}
public static TResult Dispatch<TSource, T1, T2, TResult>(this TSource source, Func<TSource, T1, T2, TResult> func, T1 param1, T2 param2) where TSource : DispatcherObject
{
if (source.Dispatcher.CheckAccess())
return func(source, param1, param2);
return (TResult)source.Dispatcher.Invoke(func, source, param1, param2);
}
public static TResult Dispatch<TSource, T1, T2, T3, TResult>(this TSource source, Func<TSource, T1, T2, T3, TResult> func, T1 param1, T2 param2, T3 param3) where TSource : DispatcherObject
{
if (source.Dispatcher.CheckAccess())
return func(source, param1, param2, param3);
return (TResult)source.Dispatcher.Invoke(func, source, param1, param2, param3);
}
public static void Dispatch(this DispatcherObject source, Action func)
{
if (source.Dispatcher.CheckAccess())
func();
else
source.Dispatcher.Invoke(func);
}
public static void Dispatch<TSource>(this TSource source, Action<TSource> func) where TSource : DispatcherObject
{
if (source.Dispatcher.CheckAccess())
func(source);
else
source.Dispatcher.Invoke(func, source);
}
public static void Dispatch<TSource, T1>(this TSource source, Action<TSource, T1> func, T1 param1) where TSource : DispatcherObject
{
if (source.Dispatcher.CheckAccess())
func(source, param1);
else
source.Dispatcher.Invoke(func, source, param1);
}
public static void Dispatch<TSource, T1, T2>(this TSource source, Action<TSource, T1, T2> func, T1 param1, T2 param2) where TSource : DispatcherObject
{
if (source.Dispatcher.CheckAccess())
func(source, param1, param2);
else
source.Dispatcher.Invoke(func, source, param1, param2);
}
public static void Dispatch<TSource, T1, T2, T3>(this TSource source, Action<TSource, T1, T2, T3> func,
T1 param1, T2 param2, T3 param3) where TSource : DispatcherObject
{
if (source.Dispatcher.CheckAccess())
func(source, param1, param2, param3);
else
source.Dispatcher.Invoke(func, source, param1, param2, param3);
}
}
That seems a lot of code to write but see how it simplifies the code when you use it:
private static void DoWork(object state)
{
Window1 win = (Window1) state;
for (int i = 0; i < 100; i++)
{
// do some work
win.progress1.Dispatch((p, v) => p.Value = v, i);
}
win.progress1.Dispatch(p => p.Value = 100);
}
This is almost as simple as our first implementation of DoWork. The only difference is in this version we call “Dispatch” with a lambda expression that will always be run on the UI thread.
Let me know if you find this helpful or if you think of something better.