2

我正在启动一个新线程并尝试通过我的视图模型中定义的属性更新 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();
    }
4

2 回答 2

7

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

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

他们打算对事件做同样的INotifyCollectionChanged事情,但在以前的版本中从未考虑过。对于 4.5 ,他们现在将自动同步集合更改事件INotifyPropertyChanged

于 2012-04-05T16:15:34.790 回答
2

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

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

        }, TaskScheduler.FromCurrentSynchronizationContext());

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

于 2012-04-05T15:53:10.807 回答