views:

1591

answers:

6

I suppose to be able to access the Dispacher that belongs to the View I need to pass it to the ViewModel. Bu the View should not known anything about the ViewModel so how do you pass it? Introduce an Interface or instead of passing it to the instances create a global dispatcher singleton that will be written by the View? How do you solve this in your MVVM applications and frameworks?

EDIT: Note that since my ViewModels might be created in background threads I can't just do Dispatcher.Current in the constructor of the ViewModel.

A: 

I get the ViewModel to store the current dispatcher as a member.

If the ViewModel is created by the view, you know that the current dispatcher at creation time will be the View's dispatcher.

class MyViewModel
{
    readonly Dispatcher _dispatcher;
    public MyViewModel()
    {
        _dispatcher = Dispatcher.CurrentDispatcher;
    }
}
Andrew Shepherd
In my scenario the ViewModels are created in threads. That's why I was asking in the first place.
bitbonk
But problematic for unit testing. How do you write this sort of code and unit test your VMs?
Ray Booysen
@Roy: See this question http://stackoverflow.com/questions/1106881/using-the-wpf-dispatcher-in-unit-tests/1303762#1303762
Andrew Shepherd
+6  A: 

I have abstracted the Dispatcher using an interface IContext:

public interface IContext
{
   bool IsSynchronized { get; }
   void Invoke(Action action);
   void BeginInvoke(Action action);
}

This has the advantage that you can unit-test your ViewModels more easily.
I inject the interface into my ViewModels using the MEF (Managed Extensibility Framework). Another possibility would be a constructor argument. However, I like the injection using MEF more.

winSharp93
Could you provide an example of an implementation in a wpf UserControl?
Femaref
+3  A: 

You may not actually need the dispatcher. If you bind properties on your viewmodel to GUI elements in your view, the WPF binding mechanism automatically marshals the GUI updates to the GUI thread using the dispatcher.


EDIT:

This edit is in response to Isak Savo's comment.

Inside Microsoft's code for handling binding to properties you will find the following code:

if (Dispatcher.Thread == Thread.CurrentThread)
{ 
    PW.OnPropertyChangedAtLevel(level);
} 
else 
{
    // otherwise invoke an operation to do the work on the right context 
    SetTransferIsPending(true);
    Dispatcher.BeginInvoke(
        DispatcherPriority.DataBind,
        new DispatcherOperationCallback(ScheduleTransferOperation), 
        new object[]{o, propName});
} 

This code marshals any UI updates to the thread UI thread so that even if you update the properties taking part of the binding from a different thread, WPF will automatically serialize the call to the UI thread.

Jakob Christensen
but there are plenty of situations, you might need to do this, Imagine an ObservableCollection bound to the UI and you trying to call _collection.Add() from a worker thread
Jobi Joy
I know. Of course, the usual theading considerations still apply.
Jakob Christensen
Currently we need the dispatcher for the sole purpose of adding items to the ObservableCollection.
bitbonk
Unless I misunderstand you jakob, this is completely wrong. The binding mechanism won't do any marshalling for you. If you update a property in the view model from a background thread, the NotifyPropertyChanged event will be raised on that background thread and the GUI will be updated on that background thread -> exception! -1 until someone proves me wrong
Isak Savo
Hi Isak. You understand me correctly but you are wrong. If you debug through Microsoft's WPF binding code (or look at it using Reflector), you will see that the code checks if you are on the GUI thread and if not it will use the Dispatcher to update on the GUI thread. I don't know if it works for ObservableCollection but it does for "normal" properties. I wrote a blog entry on this (in Danish though). At the bottom of the blog entry Microsoft's code is shown: http://www.dotninjas.dk/post/Flere-trade-og-binding-i-WPF.aspx
Jakob Christensen
Jakob: You are absolutely correct. I've modified my -1 to +1 instead. I tried this in both .net 3.5 and 4.0 and it seems it's perfectly ok to raise PropertyChanged on a background thread.
Isak Savo
Thanks, Isak :-)
Jakob Christensen
A: 

Some of my WPF projects I have faced the same situation. In my MainViewModel (Singleton instance), I got my CreateInstance() static method takes the dispatcher. And the create instance gets called from the View so that I can pass the Dispatcher from there. And the ViewModel test module calls CreateInstance() parameterless.

But in a complex multithread scenario it is always good to have an interface implementation on the View side so as to get the proper Dispatcher of the current Window.

Jobi Joy
+1  A: 

If you're only needing the dispatcher for modifying a bound collection in another thread take a look at the SynchronizationContextCollection here http://kentb.blogspot.com/2008/01/cross-thread-collection-binding-in-wpf.html

Works well, only issue I found is when using View Models with SynchronizationContextCollection properties with ASP.NET synch context, but easily worked around.

HTH Sam

sambomartin
wow, interesting, something like this should part of WPF
bitbonk
A: 

if you are used uNhAddIns you can make an asynchrounous behavior easily. take a look here

And i think need a few modification to make it work on Castle Windsor (without uNhAddIns)

ktutnik