6

My WPF application is structured using the MVVM pattern. The ViewModels will communicate asynchronously with a server, and when the requested data is returned a callback in the ViewModel is triggered, and it will do something with this data. This will run on a thread which is not the UI Thread. Sometimes these callbacks involve work that needs to be done on the UI thread, so I need the Dispatcher. This might be things such as:

  • Adding data to an ObservableCollection
  • Trigger Prism commands that will set something to be displayed in the GUI
  • Creating WPF objects of some kind.

I try to avoid the latter, but the two first points here I find to be reasonable things for ViewModels to do. So; is it okay to have ViewModels hold the Dispatcher to be able to Invoke commands for the UI thread? Or is this considered bad practice? And why?

stiank81
  • 25,418
  • 43
  • 131
  • 202
  • I have had to do the same in controllers - the controller subscribes to the Load event of the view it creates, and at that point grabs a reference to the dispatcher of the view. This is especially useful for executing delegates that have been passed around. – slugster Mar 12 '10 at 11:22
  • Thx for the tip! I'm using an IoC container, and the IoC container is created in App.xaml.cs. I'm assuming this is run in the UI thread, so the plan is to fetch the current dispatcher at the point the IoC container is created and add it to the container. Remains to see if this is successful. – stiank81 Mar 12 '10 at 11:56
  • Works perfectly. Or you can simply use Dispatcher.CurrentDispatcher at any parh you know is being run by the UI thread. Like e.g. the ViewModel constructors - if these are being constructed in the UI thread. – stiank81 Mar 12 '10 at 13:00

4 Answers4

3

Since an ObservableCollection must be updated on the thread it belongs to (assuming a GUI app), and ObservableCollections should be part of the ViewModel, then there's a clear case for the ViewModel having a Dispatcher.

I can't see it being part of the Model.

kyoryu
  • 12,848
  • 2
  • 29
  • 33
  • It should definitly not be part of the model. The workaround you can do is to create a new ObservableCollection and fill the result with this, but that really sounds like a hack to me.. – stiank81 Mar 12 '10 at 12:28
  • I have a slight variation of MVVM: My Model is unmanaged code running on worker threads. The Model calls back into my .Net code, which then dispatches onto the GUI thread. The dispatched function running in the GUI thread then updates the ViewModel. In this way, my VM doesn't need to know about dispatching. – Surfbutler Apr 22 '10 at 21:37
2

Ideally, a ViewModel should be totally independent from the UI technology used. We should theoretically be able to reuse it for Windows Forms (if we pimp up the Windows Forms controls a little bit to support better binding), for Web pages (I envision some kind of fancy mechanism here that would compile the ViewModel also into Javascript), and for any future technologies. Not all of these technologies will use the Dispatcher model.

That said, i consider it as a pragmatic compromise to include the Dispatcher in the ViewModel nowadays. In my ViewModel base class, I check for the current Dispatcher:

    protected override void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (Deployment.Current.Dispatcher == null || Deployment.Current.Dispatcher.CheckAccess())
        {
            base.OnPropertyChanged(sender, e);
        }
        else
        {
            Deployment.Current.Dispatcher.BeginInvoke(() => base.OnPropertyChanged(sender, e));
        }
    }

I still have the dependency on System.Windows of course, but oh well. :->

herzmeister
  • 11,101
  • 2
  • 41
  • 51
  • It sounds good to be able to reuse your ViewModels, but I don't really agree that this is the goal. Just consider a simple thing such as command bindings. You really need command bindings when doing MVVM, but does Winforms have ICommand? Actually I'm not sure, but earlier I wanted to make my ViewModels build on Mono, and at least Mono doesn't have ICommand.. – stiank81 Mar 12 '10 at 13:25
  • Still - valuable feedback! +1 – stiank81 Mar 12 '10 at 13:28
  • 1
    @heartmaster, if it (really) is a goal to reuse your VM, you should hide the dispatcher away behind some interface (that can also be re-implemented by WinForms InvokeRequired etc). – H H Mar 12 '10 at 13:28
  • @both, yes, the out of the box Windows Forms controls of course lack support for MVVM, as I alluded. It was just an example. And the day I srsly consider making a ViewModel reusable for other technologies, I'll make an appropriate design. But for now, the Dispatcher is out of my sight in my inherited ViewModels, and that's all that matters for me now. – herzmeister Mar 12 '10 at 14:44
  • 1
    Agree with sbank81 on reuse of ViewModels. It's not really the point. If it falls out that way, fine, but if you go into it trying to reuse your ViewModel, you're not really creating a ViewModel, you're creating a Model. Be wary of early generalization, it's often a sign of 'false laziness' - the costs and continued pain of the generalization is often more expensive than just writing a second ViewModel. – kyoryu Mar 12 '10 at 17:56
1

I agree with kyoryu and I would like to note that it only creates a dependency on the ServiceModel lobrary (which you already have) and not on the View itself, so there is very little to object against this construction.

I was trying out a few things with WPF, a simple VM and threads yesterday and came to the conclusion that I absolutely needed to pass the Dispatcher to the VM.

Also see Using WPF UI thread should always ensure STA apartment mode, right?

Community
  • 1
  • 1
H H
  • 263,252
  • 30
  • 330
  • 514
  • Thx for your answer! I'm starting to use the Dispatcher now, and it really simplifies things. Before I did this I found myself doing some very creative (hacky) solutions. Using the Dispathcer I think the code is getting a lot better. But I guess you should be aware of what you do - don't do *anything* just because you can.. – stiank81 Mar 12 '10 at 13:21
  • Pass the Dispatcher to the VM? That's probably not what I'd do. My point was that the VM might need a Dispatcher because it might own things that need to get Dipsatached. Typically, I like doing my dispatching at the last possible moment. If that's the VM, fine, if it's in the View, fine. If my View was totally xaml, I might be tempted to have the VM responsible for the Dispatcher, just to keep the View pure xaml. But that's probably over-cleverness on m part. – kyoryu Mar 12 '10 at 17:59
  • Of course, this might be because in my day job I'm working on infrastructure bits and we're trying to own the thread context., and I'm rapidly coming to the conclusion that it makes more sense to do that as close to the bits that actually care as possible, rather than centralize it... – kyoryu Mar 12 '10 at 18:00
  • I don't know if it is the best solution, but I fetch the Dispatcher at one place in the code - namely the bootstrapping of the IoC container. And then I inject it into the classes that wants it. I believe that's better for testability too. – stiank81 Mar 12 '10 at 18:36
  • @stiank81: That makes the assumption that your entire app needs the same Dispatcher. If you really care about making sure controls are updated on the proper thread, I'd do the dispatching as close to the control as possible, since it knows what it needs. – kyoryu Mar 13 '10 at 02:30
0

You should consider using AsyncOperation instead.

Monstieur
  • 7,992
  • 10
  • 51
  • 77