9

I am using .NET 3.5 .

I am making a WPF application for a project and I was just looking a bit of insight regarding the Dispatcher and multithreading. An example of my program:

Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(
                        () =>_aCollection.Add(new Model(aList[i], aSize[i]))));

Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(
                        () => _Data.Add(new DataPoint<double, double>(Id, aList[i]))));

 Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(
                        () => _historical[0].Add(aList[i])));

I understand that WPF does not like when another thread accessing an object other than the one that created it. However, I was thinking there has to surely be a better way than making so many dispatcher invokes, could someone please push me in the right direction at least (if there is a better solution that is).

peterh
  • 11,875
  • 18
  • 85
  • 108
Sparky
  • 415
  • 2
  • 5
  • 13

4 Answers4

16

You can start by being less verbose in your calls, i.e.

Application.Current.Dispatcher.Invoke(() =>_aCollection.Add(new Model(aList[i], aSize[i])));

Another trick that I like to use is to make a shortcut method like this:

public static void UiInvoke(Action a)
{
  Application.Current.Dispatcher.Invoke(a);
}

Then you have even less to do, as in:

UiInvoke(() =>_aCollection.Add(new Model(aList[i], aSize[i])));

Using dispatcher.Invoke() is really just how you get the action back onto the UI thread, which is probably where these objects (_aCollection) were created in the first place. If the items in question don't have direct interaction with the UI thread, then you can create / manipulate them on a different thread, removing the need to use the dispatcher. Of course this approach could become more complicated depending on what you are doing.

A.R.
  • 15,405
  • 19
  • 77
  • 123
  • I like this idea! Thanks. I have 2 threads running in the one class: 1 for getting data for the database, the other for issuing a RaisePropertyChanged to update the UI. I understand this probably isn't the best way of doing things, to be honest, I'm no expert in WPF so the idea of a UI Thread and backgroundWorkers is a bit foreign to me at the minute – Sparky Mar 28 '11 at 20:09
  • 1
    No, that is pretty much how things are done in WPF, so I woukd say that your approach is just fine. I will agree that it can be a pain to do the UI stuff, but a necessary evil I guess. Coding gorilla also make a good point above about the continuations, but those can get into super-slop territory so be advised. Good luck! – A.R. Mar 28 '11 at 20:51
  • I dont think this is "pretty much how things are done in WPF". Databinding should do dispatching automaticaly. Especialy if he is using MVVM. See my updated answer. – Euphoric Mar 29 '11 at 09:30
  • @Euphoric: That is all well and good for bindings, but that is clearly not the case here. Also, you can't make assumptions about the more complex interactions of his code. So you are pretty much left to do the dispatching yourself. – A.R. Mar 29 '11 at 12:30
13

The easiest way would be to combine all three calls into one:

Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(
                        () =>
                      {
                          _aCollection.Add(new Model(aList[i], aSize[i]);
                          _Data.Add(new DataPoint<double, double>(Id, aList[i]);
                          _historical[0].Add(aList[i])
                      }));
Adam Robinson
  • 182,639
  • 35
  • 285
  • 343
  • I didn't know that was possible, learn something new everyday! Cheers. – Sparky Mar 28 '11 at 20:09
  • 2
    @Sparky: All you're doing with the `=>` operator is creating a lambda expression, which is a type of anonymous delegate. These are all syntactic sugars that the compiler ends up turning into ordinary instance (or sometimes static) methods. You can do anything within a lambda expression (when it's used as an anonymous delegate, as it is here) that you can do within an ordinary function, except for (possibly; I haven't checked) `ref` and `out` parameters. – Adam Robinson Mar 28 '11 at 20:19
  • It worked for me, got rid of print exception: The calling thread cannot access this object because a different thread owns it., stacktrace: at System.Windows.Threading.Dispatcher.VerifyAccess() – digz6666 Nov 21 '14 at 11:56
6

IF you're using .Net 4.0 I would look into using System.Threading.Tasks. This seems like a prime example for continuations.

CodingGorilla
  • 19,612
  • 4
  • 45
  • 65
  • 1
    Tasks won't help if he's already outside the message pump thread (which is where the automatic synchronization would come in handy) – Adam Robinson Mar 28 '11 at 19:38
  • 5
    Sure it will, because you can schedule your "Background" tasks on a background thread and then "Finish" it up with a continuation on the UI thread like: `Task.ContinueWith(FinishMyStuff, TaskScheduler.FromCurrentSynchronizationContext)` – CodingGorilla Mar 28 '11 at 19:44
  • 1
    Sure, if the OP is in a position to move all of the current code into Tasks and place it all on the Window/Control. However, if he's not in a position to rework the entire threading model, then Tasks won't help. – Adam Robinson Mar 28 '11 at 19:55
  • 3
    @AdamRobinson Well he was asking for "insight" and he didn't offer any restrictions, so I offered up what I thought was the best "idea" I had. He's free to ignore it if he choses. – CodingGorilla Mar 28 '11 at 19:58
  • Hi Guys, Thanks so much for the replies, unfortunately I can't implement them as I'm using .Net 3.5 :) None the less, I'll research the above-mentioned for future reference! Cheers – Sparky Mar 28 '11 at 20:05
3

Your problem stems from fact, that ObservableCollection doesn't automaticaly dispatch changes to UI thread. This is different form simple INotifyPropertyChanged, that does it automaticaly. I would recomend creating your own specific ObservableCollection, that implements INotifyCollectionChanged, that automaticaly dispatches changes to UI thread.

You can see example here: SynchronizedObservableCollection and BindableCollection

Old answer/question: Are you using DependencyObject and DependencyProperties for your binding? If yes, then drop it. It was discussed many times and this is one of the bigger reasons why to use INotifyPropertyChanged instead. Only need to use dispatcher is to modify properties of GUI objects themselves and its obvious from your example, that is not what are you doing. And binding itself is run through dispatcher automaticaly.

Also see View Models: POCOs versus DependencyObjects

Euphoric
  • 12,645
  • 1
  • 30
  • 44
  • Hi Euphoric, cheers, but no, I'm not using Dependency Properties. Also, I'm using MVVM light so currently I use "RaisePropertyChanged" over "INotifyPropertyChanged." Thanks – Sparky Mar 29 '11 at 08:46
  • Thats weird. So what are _aCollection, _Data and _historical in your example? If they are not part of GUI, then there is no need to change them through Dispatcher. And I dont see ANY need to use Dispatcher when using MVVM. – Euphoric Mar 29 '11 at 09:11
  • Hmmm... Well in that case how would you get around the problem where unnamed threads are accessing an Observable Collection? _Data are chart points for Visiblox and _aCollection is an obervable collection binded by a listview – Sparky Apr 05 '11 at 14:55