在MVVM中使用WPF不需要Dispatcher吗?

时间:2012-04-05 15:32:23

标签: wpf multithreading xaml mvvm dispatcher

我正在开始一个新线程,并尝试通过我的View模型中定义的属性更新UI元素,我能够毫无错误地执行此操作,但如果我尝试通过代码隐藏更新UI元素,则会抛出已知的UI访问错误("调用线程无法访问此对象,因为另一个线程拥有它。")。第一个问题是......两种方法的区别是什么?第二个问题是我在理想情况下在ViewModel中使用Disptacher吗?

代码背后

private void Button_Click(object sender, RoutedEventArgs e)
    {
        Thread th = new Thread(new ThreadStart(delegate()
            {
                textbox.Text = "Rajib";
            }
        ));

        th.Start();
    }

//inside XAML
<TextBox x:Name="textbox" Text="{Binding UserInput, Mode=TwoWay}" />

MVVM

public string UserInput
    {
        get { return _UserInput; }
        set { _UserInput = value; OnPropertyChanged("UserInput"); }
    }

//单击按钮时通过ICommand属性调用     public void ExecuteCommand(object obj)         {             InvokeCallThroughAnonymousDelegateThread();         }

private void InvokeCallThroughAnonymousDelegateThread()
    {
        ThreadStart start = delegate()
        {
            UserInput = "Calling from diff thread";
        };           
        new Thread(start).Start();
    }

2 个答案:

答案 0 :(得分:7)

任何更新UI的尝试都必须在调度程序线程中完成。但是,对于属性更改事件,当从后台线程引发事件时,WPF 会自动为您分派。您可以在Bea Costa(以前的WPF数据绑定PM)博客上阅读更多相关信息:

http://bea.stollnitz.com/blog/?p=34

他们将为INotifyCollectionChanged事件做同样的事情,但在之前的版本中从未接触到它。对于4.5 they will now be synchronizing collection changed events automatically以及INotifyPropertyChanged

答案 1 :(得分:2)

NotifyPropertyChanged通过事件由WPF更改了其线程上下文,但是后面的代码不会将线程上下文更改为UI线程。在您的代码隐藏中,请改用:

Task.Factory.StartNew(() =>
        {
            // Background work
        }).ContinueWith((t) => {
            // Update UI thread

        }, TaskScheduler.FromCurrentSynchronizationContext());

关于何时直接使用Dispatcher,我有一个中型项目,我没有在任何ViewModel中使用Dispatcher。我用它来处理Xaml资源,弱事件处理,并在MefedMVVM和Prism中使用它,我也使用它。