Useful WPF Threading Extension Method
If you are working with WinForms or WPF you will more than likely run into some long running operation that you would like to run in a new thread. A novice may actually try and create a new Thread, which is ok, but that means you are responsible for the entire lifecycle of your new thread. Which gets tricky.
A better approach would be to use the ThreadPool or use a BackgroundWorker component which uses the ThreadPool beneath the surface.
However, even using these approaches the cardinal rule is that the control is owned by 1 thread, the thread that created the controls. That is typically the UI thread. So when you try and update the controls from a background thread you will run into problems.
This code demonstrates the problem with cross thread calls :
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5: using System.Windows;
6: using System.Windows.Controls;
7: using System.Windows.Data;
8: using System.Windows.Documents;
9: using System.Windows.Input;
10: using System.Windows.Media;
11: using System.Windows.Media.Imaging;
12: using System.Windows.Navigation;
13: using System.Windows.Shapes;
14: using System.ComponentModel;
15: using System.Windows.Threading;
16:
17: namespace BackgroundThread
18: {
19:
20:
21: public partial class Window1 : Window
22: {
23: private Int32 currentCount = 0;
24: private Int32 maxCount = 500;
25: private float factor = 0;
26:
27: public Window1()
28: {
29: InitializeComponent();
30:
31: }
32:
33: private void btnGo_Click(object sender, RoutedEventArgs e)
34: {
35: factor = (float)100 / maxCount;
36:
37: BackgroundWorker bgWorker = new BackgroundWorker();
38: bgWorker.WorkerReportsProgress = true;
39: bgWorker.WorkerSupportsCancellation = false;
40:
41: //DoWork
42: bgWorker.DoWork += (s2, e2) =>
43: {
44: for (currentCount = 0;
45: currentCount < maxCount; currentCount++)
46: {
47: lstItems.Items.Add(
48: String.Format("Count {0}", currentCount));
49: }
50: };
51:
52: //ProgressChanged
53: bgWorker.ProgressChanged += (s3, e3) =>
54: {
55: pgbar.Value = e3.ProgressPercentage;
56: };
57:
58: bgWorker.RunWorkerAsync();
59:
60: }
61: }
62: }
Which when run will result in the following:
So how can we fix this, well we could use the Dispatcher.Invoke around the offending items, but perhaps a more elegant solution may be to use a extension method.
1: public static class WPFThreadingExtensions
2: {
3: /// <summary>
4: /// Simple helper extension method to marshall to correct
5: /// thread if its required
6: /// </summary>
7: /// <param name="control">The source control</param>
8: /// <param name="methodcall">The method to call</param>
9: /// <param name="priorityForCall">The thread priority</param>
10: public static void InvokeIfRequired(
11: this DispatcherObject control,
12: Action methodcall,
13: DispatcherPriority priorityForCall)
14: {
15: //see if we need to Invoke call to Dispatcher thread
16: if (control.Dispatcher.Thread != Thread.CurrentThread)
17: control.Dispatcher.Invoke(priorityForCall, methodcall);
18: else
19: methodcall();
20: }
21: }
Which we can then use in our code as simply as follows :
1: factor = (float)100 / maxCount;
2:
3: BackgroundWorker bgWorker = new BackgroundWorker();
4: bgWorker.WorkerReportsProgress = true;
5: bgWorker.WorkerSupportsCancellation = false;
6:
7: //DoWork
8: bgWorker.DoWork += (s2, e2) =>
9: {
10: for (currentCount = 0;
11: currentCount < maxCount; currentCount++)
12: {
13:
14: this.InvokeIfRequired(() =>
15: {
16: lstItems.Items.Add(
17: String.Format("Count {0}", currentCount));
18: },
19: DispatcherPriority.Background);
20:
21: bgWorker.ReportProgress((int)(factor * (currentCount + 1)));
22:
23: }
24: };
25:
26: //ProgressChanged
27: bgWorker.ProgressChanged += (s3, e3) =>
28: {
29: this.InvokeIfRequired(() =>
30: {
31: pgbar.Value = e3.ProgressPercentage;
32: },
33: DispatcherPriority.Background);
34:
35:
36: };
37:
38: bgWorker.RunWorkerAsync();
39:
40: }
Which when run allows cross threaded calls to be marshaled to the correct Dispatcher object.
Hope this helps.


























Josh Smith said
am January 19 2009 @ 8:29 pm
Nice!
sacha said
am January 19 2009 @ 8:41 pm
Thanks Josh.
WPF-BASICS: Loading large datasets - Rudi Grobler said
am January 20 2009 @ 6:19 am
[...] [UPDATE] Sacha Barber has a excellent new post about BackgoundWorker + WPF, read more here [...]
Bruno MartÃnez said
am January 20 2009 @ 11:52 am
I don’t think there’s an advantage over using the Dispatcher directly. Look at
internal object InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, object args, bool isSingleParameter)
in Reflector. The case in which the dispatcher belongs to the current thread is already handled.
sacha said
am January 20 2009 @ 12:37 pm
Thats true, but there is an overhead in calling Invoke so you should not do so unless you have to.
Richard Wilburn said
am January 22 2009 @ 5:32 am
Your extension method is cool, but perhaps is better used only with winforms? I find the use case for your method questionable with WPF best practices. If you use a Model-View-ViewModel architecture you would never interact with the view directly; rather the view-model.
sacha said
am January 22 2009 @ 6:31 am
Actually the same applies even using the MVVM pattern, which we use all the time on my current project. You are still having to marshall stuff back to the UI thread from time to time, as we are calling sessionful WCF services that sometimes use different threads, so they data that comes back MUST be marshaled back to the UI thread.
See what I mean.
Yoiu should read up on the MVPoo pattern, Dr WPF talks about it a bit, and I am lucky enough to be part of a very good WPF group called the WPF Disciples that have many Microsoft Architects and Program managers and tool creators in it, and we all agree no matter how much you try there will always be something trying to make your pure pattern a bit stinky with some UI poo in there somewhere.
Miguel said
am March 30 2009 @ 6:42 am
Ey, great job.
Thank you.
sacha said
am March 30 2009 @ 7:31 am
Thanks man
Kevin said
am April 1 2009 @ 6:10 pm
Nice post!
In response to Richard’s comment, another technique is to use a DelegateMarshaler from this article:
http://blog.quantumbitdesigns.com/2008/07/22/delegatemarshaler-replace-controlinvokerequired-and-controlinvoke/
That way Models and/or ViewModels do not need references to any ‘controls.’ I, like Richard, do not like any interaction with ‘views’ in my VM layer.
This is example usage:
marshaler.Invoke(ShowDownloadComplete, fileName);
BTW, the blog post formatting was lost in a crash, I need to fix it some day.
Kevin
sacha said
am April 1 2009 @ 6:36 pm
Kevin
Thanks for the link, however I am not sure this would work with WPF as there is no SynchronizationContext to speak of, the Dispatcher deals with it.
I could be wrong, but I feel what I say is correct.
What you show is ace for Winforms though.
Kevin said
am April 2 2009 @ 4:13 pm
WPF has a DispatcherSynchronizationContext that gets loaded for WPF apps when Dispatcher.Run() is called (which is called eventually by Application.Run())
Therefore, WPF ViewModels do not need window references, which I love.
sacha said
am April 2 2009 @ 4:18 pm
Cool thanks for that Kevin, I was not actually aware of the DispatcherSynchronizationContext class
Jasvinder said
am June 6 2009 @ 4:47 am
Nice post Sacha.I Like your way of coding.
sacha said
am June 6 2009 @ 7:00 am
Thanks Jasvinder
Yazid said
am August 22 2009 @ 10:51 pm
Sacha
Great article, by any chance do you an example which combines the technique you describe here and MVVM
TIA
Yaz
dumbledad said
am December 8 2009 @ 9:52 am
Great post, pithy and useful. Thanks. What are you doing if the invoked method call has arguments so that the ‘Action methodcall’ argument in your extension method is inadequate?
sacha said
am December 8 2009 @ 10:15 am
I would just create another extension method that took a Action say
dumbledad said
am December 8 2009 @ 1:44 pm
But isn’t Action for parameterless calls?
Brian Winkleman said
am March 12 2010 @ 6:12 am
What would be really neat is an example of a background worker against a database that you can actually cancel. Oracle database that is. Just would like to be able to kill a long running query. The users today close the application and open it again.
thanks
sacha said
am March 12 2010 @ 7:21 am
That would be quite hard, as background threads are normally started on UI, and actually done on server. So the call to the server could be cancelled, but once its started the DB call, how do you cancel it. Thats the bit that takes the time actually.
MLL said
am March 12 2010 @ 3:34 pm
Excellent info for this particular scenario. Do you have any advice for this one?
WPF+VB.NET
Concept:
Pure custom controls where -any- of the properties may be hit by any number of threads. The UI style(s) use TemplateBinding against the relevant properties. I have used safe threading extensively for years both in Win Forms and now in WPF. But in this case I’m looking for a more elegant solution than having to create a batch of delegates if possible.
Obviously I can’t use anon delegates yet (/me sniffs) and I would very much like to avoid having to create a slew of delegates if possible. I could probably manage this by using reflection / other techniques to dynamically build one for the call but then the overhead of that would get out of hand pretty fast.
My current understanding is we can not use the Lambda Function() for it because.. that’s not what it’s for. It’s a function and therefore must return a value and can not be used to simulate an anon delegate sub in this case.
Thanks for any advice or links to possible solutions.
PS: An answer of “use C#?” won’t solve the problem
sacha said
am March 12 2010 @ 3:43 pm
Pure custom controls where -any- of the properties may be hit by any number of threads
Mmmm that would be hard, as you can never get out of having to marshall to UI thread if you have to do it, you have to do it.
As for an elegant technique, I’m afraid not. As for Lamdas, they do not always have to return a value, for example I could have something like this
Button.Click += (s,e) => { MessageBox.Show(”Clicked”); };
That does not return anything, but its a lambda.
I am afraid it all marshalling hard work for you.
MLL said
am March 12 2010 @ 3:55 pm
Yeah that’s what I assumed but wanted to confirm it before I go down that road if I didn’t have/need to.
I know I can not escape the requirement to marshal calls to the owning thread that is a given (and I actually understand why, and have for a long time). I’m simply wanting to do it in a more generic way than having to explicitly define delegates.
Yep I’ve tried an approach such as this with Lambda but the call is never actually made, though it does process it without complaint:
Application.Current.Dispatcher.Invoke(Function() (Message = value))
However in this case I believe it is actually evaluating it as an expression testing if Message = Value instead of setting it.
I appreciate your response thanks!