2012-01-29 8 views
2

私はMVVMには比較的新しいので、INotifyPropertyChangedインターフェイスがどのように動作するのか、それを自分のモデルに実装する方法を理解しようとしています。私が取ることに決めたアプローチは、それぞれのビジネスオブジェクトクラスに実装することでした。
このアプローチの問題は、ビューをBaseクラスのプロパティにバインドすると、その基本クラスのPropertyChangedイベントが初期化されることはなく(null)、モデルが変更されたときにそのビューのデータが更新されない。私は以下の例で問題を再現することができました。MVVM INotifyProperty基本クラスとの変更された不具合PropertyChange

私は人基底クラスを持っている:

public class Person : INotifyPropertyChanged 
    { 
     #region INotifyProperty 

     public event PropertyChangedEventHandler PropertyChanged; 

     public void RaisePropertyChanged(string propertyName) 
     { 
      if (PropertyChanged != null) 
      { 
       PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
      } 
     } 
     #endregion 

     public String Name 
     { 
      get 
      { 
       return _name; 
      } 
      set 
      { 
       _name = value; 
       RaisePropertyChanged("Name"); 
      } 
     } 
     private String _name; 
    } 

そして、私は私の個人基本クラスから継承するEmployeeクラスを持っている:

​​3210

ここに私のビューモデル:

public class ViewModel : ViewModelBase<ViewModel> 
    { 
     private Employee _employee; 

     public ViewModel() 
     { 
      ChangeModelCommand = new RelayCommand(param=>this.ChangeModel() , param=>this.CanChangeModel); 
      Employee = new Employee() 
         { 
          Name = "BOB",EmployeeID = "1234" 
         }; 
     } 

     public ICommand ChangeModelCommand { get; set; } 


     public Employee Employee 
     { 
      get 
      { 
       return _employee; 
      } 
      set 
      { 
       this._employee = value; 
       NotifyPropertyChanged(m=>m.Employee); 
      } 
     } 

     public void ChangeModel() 
     { 
      MessageBox.Show("CHANGING MODEL"); 
      this.Employee.Name = "MIKE"; 
      this.Employee.EmployeeID = "5678"; 
     } 
     public bool CanChangeModel 
     { 
      get{ return true;} 
     } 
    } 

を最後に私のビュー:

<Window.Resources> 
    <MVVM_NotificationTest:ViewModel x:Key="Model"></MVVM_NotificationTest:ViewModel> 
</Window.Resources> 
<Grid DataContext="{StaticResource Model}"> 
<StackPanel> 
    <Label Content="Employee Name"/> 
    <TextBox Text="{Binding  Path=Employee.Name,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/> 
    <Label Content="Employee ID"/> 
    <TextBox Text="{Binding Path=Employee.EmployeeID,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/> 
    <Button Content="Change Model" Height="30" Width="100" Margin="5" Command="{Binding Path=ChangeModelCommand}"/> 
</StackPanel> 
</Grid> 

この例では、VMコンストラクタでEmployee VMプロパティを初期化してからEmployeeID(Employeeクラスから)とName(Person Classから)を変更するコマンドがあります。ただし、更新されるビュー内の唯一のUI要素は、EmployeeIDであり、名前ではありません(私はBobがMikeに更新することを期待していました)。

デバッグ中、PropertyChangedイベントがベースクラス(Person)で常にnullであることがわかりました。また、Base Typeイベントとメソッドを使用しているため、Employeeクラスから#INotifyProperty領域全体を削除すると、すべて正常に動作することに気付きました。

私が持っている問題は、すべての現在のモデルクラスが明示的にINotifyPropertyChangedを実装していることです。それらはすべてPropertyChangedイベントを定義し、RaisePropertyChangedメソッドを実装します。これは明らかに私のMVVMアプリケーションでのバインディングに影響を与えます。

最後に、私のViewModelでModelプロパティをラップしてVM INPCメカニズムに依存しないことを明確にしたいと思います。私は、ベース型から継承しているかどうかに応じて、INPC実装を条件付きで削除しなくても、すでにモデルINPC実装を使用したいと考えています。

要約すると、この例で見たように継承がPropertyEventの伝播を壊さないように、私の独立したクラスは自立することができるように、深く階層的なモデルでINPCを実装する最良の方法は何ですか同じように。任意のアイデアや提案は非常に高く評価されます:)

答えて

5

単にRaisePropertyChangedをprotectedにして、それを基本クラスに移動します。現在、必要でない複製がたくさんあります。このような

何か:

protected virtual void RaisePropertyChanged(string propertyName); 

多くのMVVMフレームワークはあなたのためにこれを提供しています。たとえば、PRISMにはNotificationObject ViewModel基底クラスがあります。

+0

正確には私が考えていたもの:p –

+0

こんにちは@リチャードド、私はそれを試みたが、動作していないようだ。それは、PropertyChanged偶数宣言とRaisePropertyChangedメソッドの両方を基本クラスに移動するときにのみ機能します。 –

+0

これは、クラスが動的に生成されるため、INPC実装が各クラスに大量に追加されています。これが解決策であれば、基本クラスから継承されたときに実装を排除するためのより複雑なロジックが必要になるでしょう:( –

2

INPCを一度実装するだけで、サブクラスで同じ引き上げ方法を使用できます。

2

また、ハードコードされた文字列を渡す代わりにリフレクションを使用するように、raiseプロパティ変更メソッドを変更しました。私はあなたのビューモデルでは、あなたのモデル(エラーのほとんどが発生する傾向がある)ではなく、それをした参照してください。

+0

それは良い観測@tsellsです。その理由は、Tony SneedのSimple MVVM FrameworkのViewModelBaseを使用しているからです。これは、INPCと同じ意味です。私のモデルクラスはあなたのようにタイプミスを避けるために同様の方法でそれを実装する必要があります。 –

+1

明快にするために、Simple MVVM Toolkitには、INotifyPropertyChangedを実装する基本クラスがあり、タイプセーフなプロパティ名(文字列ではありません)のラムダ式を受け入れるNotifyPropertyChangedメソッドがあります。また、このメソッドはUIスレッドへの呼び出しをマーシャリングします。 –

+2

NotifyPropertyWeaverもご覧ください。 http://code.google.com/p/notifypropertyweaver/ – doerig

関連する問題