2009-08-24 5 views
15

방금 ​​백그라운드 작업 스레드에서 내 ViewModel (MVVM)의 바운드 속성을 변경할 때 예외가 없으며보기가 올바르게 업데이트됩니다. 이것은 UI 스레드에 ViewModel의 모든 변경 사항을 마샬링하는 wpf 데이터 바인딩에 안전하게 의존 할 수 있다는 것을 의미합니까? 나는 어딘가에 (ViewModel에서) INotifyPropertyChanged.PropertyChanged이 UI 스레드에서 실행되어야한다는 것을 읽은 것으로 생각한다. 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 스레드에서 해당 propertychanges를 읽어야하는 것은 처음입니다 : http://blogs.msdn.com/dancre/archive/2006/07/23/676300.aspx – bitbonk

1

나는 2.0 및 .NET의 이전 화신 당신 때문에 InvalidOperationException이받은 것이라고 생각 (비트 링크가 게시 한 링크는 2006 년).

이제 3.5에서는 WPF가 백그라운드 스레드 속성 변경을 마샬링하여 디스패처로 보입니다.

즉, 간단히 말해서 대상으로 삼는 .NET 버전에 따라 다릅니다. 바라건대 그 모든 혼란을 해결합니다. 내 동료 Lab49'ers의

하나는 2007 년에 여기에 대해 블로그 :

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

+0

그러나 2.0에는 WPF가 없으므로 3.0을 의미합니까? – bitbonk