How to pass the UI Dispatcher to the ViewModel

前端 未结 16 569
独厮守ぢ
独厮守ぢ 2020-11-28 02:16

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

相关标签:
16条回答
  • 2020-11-28 02:33

    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

    0 讨论(0)
  • 2020-11-28 02:35

    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;
        }
    }
    
    0 讨论(0)
  • 2020-11-28 02:37

    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)

    0 讨论(0)
  • 2020-11-28 02:38

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

    0 讨论(0)
  • 2020-11-28 02:42

    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.

    0 讨论(0)
  • 2020-11-28 02:48

    As of WPF version 4.5 one can use CurrentDispatcher

    Dispatcher.CurrentDispatcher.Invoke(() =>
    {
        // Do GUI related operations here
    
    }, DispatcherPriority.Normal); 
    
    0 讨论(0)
提交回复
热议问题