2009-08-24 19 views
15

私は、背景のワーカースレッドからViewModel(MVVM)のバウンドプロパティを変更するときに例外が発生せず、ビューが正しく更新されていることに気付きました。つまり、ViewModelのすべての変更をUIスレッドにマーシャリングするwpfデータバインディングに安全に頼ることができますか?私は、INotifyPropertyChanged.PropertyChangedがUIスレッドで起動されることを(ViewModelでは)確かめなければならないと読んだと思います。これは3.5などで変更されましたか?WPFデータバインディング・マーシャルはUIスレッドに変更されますか?

答えて

12

スカラーの場合ははい、コレクションの場合はありません。コレクションの場合は、マーシャリングする特別なコレクション、またはDispatcherを使用して手動でUIスレッドに手動でマーシャリングする必要があります。

INotifyPropertyChanged.PropertyChangedではないため、INotifyCollectionChanged.CollectionChangedはUIスレッドで起動する必要があります。以下は、あなたのためにWPFマーシャリングプロパティの変更を証明する非常に簡単な例です。

Window1.xaml.cs

using System.ComponentModel; 
using System.Threading; 
using System.Windows; 

namespace WpfApplication1 
{ 
    public partial class Window1 : Window 
    { 
     private CustomerViewModel _customerViewModel; 

     public Window1() 
     { 
      InitializeComponent(); 
      _customerViewModel = new CustomerViewModel(); 
      DataContext = _customerViewModel; 

      var thread = new Thread((ThreadStart)delegate 
      { 
       while (true) 
       { 
        Thread.Sleep(2000); 
        //look ma - no marshalling! 
        _customerViewModel.Name += "Appended"; 
        _customerViewModel.Address.Line1 += "Appended"; 
       } 
      }); 

      thread.Start(); 
     } 
    } 

    public abstract class ViewModel : INotifyPropertyChanged 
    { 
     public event PropertyChangedEventHandler PropertyChanged; 

     protected void OnPropertyChanged(string propertyName) 
     { 
      var handler = PropertyChanged; 

      if (handler != null) 
      { 
       handler(this, new PropertyChangedEventArgs(propertyName)); 
      } 
     } 
    } 

    public class CustomerViewModel : ViewModel 
    { 
     private string _name; 
     private AddressViewModel _address = new AddressViewModel(); 

     public string Name 
     { 
      get { return _name; } 
      set 
      { 
       if (_name != value) 
       { 
        _name = value; 
        OnPropertyChanged("Name"); 
       } 
      } 
     } 

     public AddressViewModel Address 
     { 
      get { return _address; } 
     } 
    } 

    public class AddressViewModel : ViewModel 
    { 
     private string _line1; 

     public string Line1 
     { 
      get { return _line1; } 
      set 
      { 
       if (_line1 != value) 
       { 
        _line1 = value; 
        OnPropertyChanged("Line1"); 
       } 
      } 
     } 
    } 
} 

Window1.xaml

<Window x:Class="WpfApplication1.Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="Window1" Height="300" Width="300"> 
    <StackPanel> 
     <TextBox Text="{Binding Name}"/> 
     <TextBox Text="{Binding Address.Line1}"/> 
    </StackPanel> 
</Window> 
+0

どのような複雑なスカラー型は? ViewModelに「MyCompositeObject」タイプのプロパティがある場合はどうなりますか? – bitbonk

+0

はい、そのパスにコレクションがない限り、プロパティパスに沿った変更はすべて正しくマーシャリングされます。 –

+0

UIのスレッド上にそのプロパティの変更を読み込んだのは初めてです:http://blogs.msdn.com/dancre/archive/2006/07/23/676300.aspx – bitbonk

1

私は.NETの2.0と以前の化身であなたが原因と、InvalidOperationExceptionを受けているだろうと信じています上記の例を実行したときのスレッドの親和性(bitbonkの投稿リンクは2006年)です。

3.5では、WPFがバックグラウンドスレッドのプロパティ変更をマーシャリングしてディスパッチャに表示されます。

つまり、要するに、対象とする.NETのバージョンによって異なります。混乱がなくなることを願っています。

私の仲間Lab49'ersの一つはここに2007年にそれについてブログ:

http://blog.lab49.com/archives/1166

+0

しかし、2.0にはWPFがありませんでした。3.0を意味しますか? – bitbonk

関連する問題