77

I'm supposed to be able to access the Dispatcher that belongs to the View I need to pass it to the ViewModel. But the View should not know 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.

Adi Lester
  • 24,731
  • 12
  • 95
  • 110
bitbonk
  • 48,890
  • 37
  • 186
  • 278

16 Answers16

47

why would not you use

 System.Windows.Application.Current.Dispatcher.Invoke(
         (Action)(() => {ObservableCollectionMemeberOfVM.Add("xx"); } ));

instead of keeping reference to GUI dispatcher.

ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
Vitaliy Markitanov
  • 2,205
  • 1
  • 24
  • 23
47

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.

Update (example from pastebin link in comments):

public sealed class WpfContext : IContext
{
    private readonly Dispatcher _dispatcher;

    public bool IsSynchronized
    {
        get
        {
            return this._dispatcher.Thread == Thread.CurrentThread;
        }
    }

    public WpfContext() : this(Dispatcher.CurrentDispatcher)
    {
    }

    public WpfContext(Dispatcher dispatcher)
    {
        Debug.Assert(dispatcher != null);

        this._dispatcher = dispatcher;
    }

    public void Invoke(Action action)
    {
        Debug.Assert(action != null);

        this._dispatcher.Invoke(action);
    }

    public void BeginInvoke(Action action)
    {
        Debug.Assert(action != null);

        this._dispatcher.BeginInvoke(action);
    }
}
TheBlueSky
  • 5,526
  • 7
  • 35
  • 65
Matthias
  • 12,053
  • 4
  • 49
  • 91
19

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
  • 14,826
  • 2
  • 51
  • 81
  • 10
    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 Mar 01 '10 at 08:58
  • I know. Of course, the usual theading considerations still apply. – Jakob Christensen Mar 01 '10 at 09:01
  • 3
    Currently we need the dispatcher for the sole purpose of adding items to the ObservableCollection. – bitbonk Mar 01 '10 at 09:25
  • 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 Apr 16 '10 at 06:12
  • 3
    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 Apr 16 '10 at 09:27
  • 1
    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 Sep 16 '10 at 10:51
  • This isn't true for Silverlight for Windows Phone 7 at least. I raised my property changed event in the background thread and got the cross-thread exception. – TheBlueSky Jul 28 '12 at 06:13
17

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
  • 44,254
  • 30
  • 139
  • 205
7

As of MVVM Light 5.2, the library now includes a DispatcherHelper class in GalaSoft.MvvmLight.Threading namespace that exposes a function CheckBeginInvokeOnUI() that accepts a delegate and runs it on the UI thread. Comes in very handy if your ViewModel is running some worker threads which affect VM properties to which your UI elements are bound.

DispatcherHelper must be initialized by calling DispatcherHelper.Initialize() at an early stage in the life of your application (e.g. App_Startup). You can then run any delegate (or lambda) using the following call:

DispatcherHelper.CheckBeginInvokeOnUI(
        () =>
        {
           //Your code here
        });

Note that the class is defined in GalaSoft.MvvmLight.Platform library which is not referenced by default when you add it through NuGet. You must manually add a reference to this lib.

dotNET
  • 33,414
  • 24
  • 162
  • 251
  • DispatcherHelper.CheckBeginInvokeOnUI used but datagrid load large amount of Data then UI hang why? – Ghotekar Rahul Dec 19 '20 at 08:42
  • `DispatcherHelper` is only meant to marshal your calls across to the UI thread. You use it AFTER your worker thread has finished the job. It doesn't magically reduce load times, nor does it somehow make the `DataGrid` load data any faster. It just gets rid of the infamous "illegal cross-thread call to the UI" exception. For improving your UI responsiveness, look into `async`/`await` pattern along with virtualization support in WPF `DataGrid`. – dotNET Dec 19 '20 at 11:59
  • Datagrid load data very slow using observable collection – Ghotekar Rahul Dec 19 '20 at 12:11
  • Do not load thousands of rows in the grid at the same time. Also if you do not need cell level editing, you may better be off using a standard `ListBox`. If you must use `DataGrid`, use some sort of paging to minimize the amount of data you need to show at a time. – dotNET Dec 19 '20 at 12:56
  • BTW, post a new question if you need help for your particular scenario. Comments are only supposed to be related to the posted question or answer or making it better in some respect. – dotNET Dec 19 '20 at 12:57
  • Ok Thank You Please Tell me Perfect Way to used DispatcherHelper.CheckBeginInvokeOnUI in Coding ? – Ghotekar Rahul Dec 19 '20 at 14:18
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/226173/discussion-between-ghotekar-rahul-and-dotnet). – Ghotekar Rahul Dec 19 '20 at 14:19
5

Another common pattern (which is seeing much use now in the framework) is the SynchronizationContext.

It enables you to dispatch synchronously and asynchronously. You can also set the current SynchronizationContext on the current thread, meaning it is easily mocked. The DispatcherSynchronizationContext is used by WPF apps. Other implementations of the SynchronizationContext are used by WCF and WF4.

  • 2
    This is the best and easiest method, I think. You can default the ViewModel's SynchronizationContext to the thread's current context in which the ViewModel was created, and, if a UserControl needs to change it, they can change it at will. – qxn Apr 16 '12 at 16:49
3

As of WPF version 4.5 one can use CurrentDispatcher

Dispatcher.CurrentDispatcher.Invoke(() =>
{
    // Do GUI related operations here

}, DispatcherPriority.Normal); 
ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
1

for WPF and Windows store apps use:-

       System.Windows.Application.Current.Dispatcher.Invoke((Action)(() => {ObservableCollectionMemeberOfVM.Add("xx"); } ));

keeping reference to GUI dispatcher is not really the right way.

if that doesn't work (such as in case of windows phone 8 apps) then use:-

       Deployment.Current.Dispatcher
1

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
  • 6,663
  • 7
  • 40
  • 64
1

hi maybe i am too late since it has been 8 months since your first post... i had the same proble in a silverlight mvvm applicatioin. and i found my solution like this. for each model and viewmodel that i have, i have also a class called controller. like that

public class MainView : UserControl  // (because it is a silverlight user controll)
public class MainViewModel
public class MainController

my MainController is in charge of the commanding and the connection between the model and viewmodel. in the constructor i instanciate the view and its viewmodel and set the datacontext of the view to its viewmodel.

mMainView = new MainView();
mMainViewModel = new MainViewModel();
mMainView.DataContext = mMainViewModel; 

//(in my naming convention i have a prefix m for member variables)

i also have a public property in the type of my MainView. like that

public MainView View { get { return mMainView; } }

(this mMainView is a local variable for the public property)

and now i am done. i just need to use my dispatcher for my ui therad like this...

mMainView.Dispatcher.BeginInvoke(
    () => MessageBox.Show(mSpWeb.CurrentUser.LoginName));

(in this example i was asking my controller to get my sharepoint 2010 loginname but you can do what your need)

we are almost done you also need to define your root visual in the app.xaml like this

var mainController = new MainController();
RootVisual = mainController.View;

this helped me by my application. maybe it can help you too...

Albin Sunnanbo
  • 46,430
  • 8
  • 69
  • 108
1

You don't need to pass the UI Dispatcher to the ViewModel. The UI Dispatcher is available from the current application singleton.

App.Current.MainWindow.Dispatcher

This will make your ViewModel dependent on the View. Depending on your application, that may or may not be fine.

Rana Ian
  • 724
  • 7
  • 6
0

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
  • 6,882
  • 1
  • 29
  • 34
0

No need to pass dispatcher when you can access application dispatcher using

Dispatcher dis = Application.Current.Dispatcher 
Hemant
  • 23
  • 3
0

I've find another (most simplest) way:

Add to view model action that's should be call in Dispatcher:

public class MyViewModel
{
    public Action<Action> CallWithDispatcher;

    public void SomeMultithreadMethod()
    {
        if(CallWithDispatcher != null)
            CallWithDispatcher(() => DoSomethingMetod(SomeParameters));
    }
}

And add this action handler in view constructor:

    public View()
    {
        var model = new MyViewModel();

        DataContext = model;
        InitializeComponent();

        // Here 
        model.CallWithDispatcher += act => _taskbarIcon.Dispatcher
            .BeginInvoke(DispatcherPriority.Normal, act) ;
    }

Now you haven't problem with testing, and it's easy to implement. I've add it to my site

Alexander Molodih
  • 1,928
  • 2
  • 20
  • 30
-1

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
  • 49,102
  • 20
  • 108
  • 119
-1

Maybe I am a bit late to this discussion, but I found 1 nice article https://msdn.microsoft.com/en-us/magazine/dn605875.aspx

There is 1 paragraph

Furthermore, all code outside the View layer (that is, the ViewModel and Model layers, services, and so on) should not depend on any type tied to a specific UI platform. Any direct use of Dispatcher (WPF/Xamarin/Windows Phone/Silverlight), CoreDispatcher (Windows Store), or ISynchronizeInvoke (Windows Forms) is a bad idea. (SynchronizationContext is marginally better, but barely.) For example, there’s a lot of code on the Internet that does some asynchronous work and then uses Dispatcher to update the UI; a more portable and less cumbersome solution is to use await for asynchronous work and update the UI without using Dispatcher.

Assume if you can use async/await properly, this is not an issue.

hardywang
  • 4,864
  • 11
  • 65
  • 101