2012-04-05 91 views
2

我开始一个新的线程,并试图通过我的视图模型中定义的属性来更新UI元素,我能够做到没有任何错误,但是如果我尝试通过代码隐藏更新UI元素,它会抛出已知的UI访问错误(“调用线程不能访问此对象,因为不同的线程拥有它。”)。第一个问题是......这两种方法之间有什么区别?第二个问题是当我在ViewModel中理想地使用Disptacher时?在WPF中,MVVM模板中不需要Dispatcher吗?

代码后面

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属性称为点击 公共无效ExecuteCommand(obj对象) { InvokeCallThroughAnonymousDelegateThread(); }

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

回答

7

任何尝试更新UI必须在调度程序线程内完成。但是,对于属性更改事件,WPF 将在您从后台线程引发事件时自动为您分配。你可以阅读更多有关这在BEA哥斯达黎加的(原WPF数据绑定PM)博客:

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

他们要为INotifyCollectionChanged事件做相同的,但从来没有得到解决它在以前的版本。对于4.5 they will now be synchronizing collection changed events automatically除了INotifyPropertyChanged

2

的NotifyPropertyChanged具有通过事件的WPF改变了它的线程上下文,但后面的代码不会更改线程上下文到UI线程。在你的代码隐藏,而是使用这样的:

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

     }, TaskScheduler.FromCurrentSynchronizationContext()); 

关于何时直接使用分派器,我有一个中等规模的项目,我没有使用过调度员在任何视图模型。我用它来处理Xaml资源,弱事件处理,并且它被用在MefedMVVM和Prism中,我也使用它。