How to pass the UI Dispatcher to the ViewModel

2020-01-25 04:05发布

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.

15条回答
对你真心纯属浪费
2楼-- · 2020-01-25 04:12

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.

查看更多
forever°为你锁心
3楼-- · 2020-01-25 04:12

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;
    }
}
查看更多
Summer. ? 凉城
4楼-- · 2020-01-25 04:15

As of WPF version 4.5 one can use CurrentDispatcher

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

}, DispatcherPriority.Normal); 
查看更多
ら.Afraid
5楼-- · 2020-01-25 04:16

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)

查看更多
我想做一个坏孩纸
6楼-- · 2020-01-25 04:17

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...

查看更多
你好瞎i
7楼-- · 2020-01-25 04:20

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

查看更多
登录 后发表回答