2017-06-02 6 views
0

私は単純なWPFアプリケーションを持っています。なぜNotifyOfPropertyChange()が予期したとおりに動作しないのかを知りたいと思います。私は2つのプロパティと1つのボタンを持つMainWindowViewModelを持っています。ボタンをクリックすると、NotifyOfPropertyChange()を呼び出してすべてのプロパティが変更されたことを通知します。また、私はViewModelにコンストラクタでコンパイルしたプロパティのリストを持っている:コンストラクタでNotifyOfPropertyChange()がviewmodelのプロパティを通知していない

properties = typeof(MainWindowViewModel).GetProperties() 
    .Where(p => p.DeclaringType == typeof(MainWindowViewModel)); 

を、私はのPropertyChangedに加入している:ここで

PropertyChanged += (sender, args) => 
{ 
    if (properties.Any(p => p.Name == args.PropertyName)) 
     IsDirty = true; 
}; 

は私の全体のMainViewModelです:

public class MainWindowViewModel : Screen 
{ 
    private string name; 
    private IEnumerable<PropertyInfo> properties; 

    public string Name 
    { 
     get { return name; } 
     set 
     { 
      name = value; 
      NotifyOfPropertyChange(() => Name); 
     } 
    } 

    private int age; 

    public int Age 
    { 
     get { return age; } 
     set 
     { 
      age = value; 
      NotifyOfPropertyChange(() => Age); 
     } 
    } 

    private bool isDirty; 

    public bool IsDirty 
    { 
     get { return isDirty; } 
     set 
     { 
      isDirty = value; 
      NotifyOfPropertyChange(() => IsDirty); 
     } 
    } 

    public MainWindowViewModel() 
    { 
     // get list of class properties 
     properties = typeof(MainWindowViewModel).GetProperties() 
      .Where(p => p.DeclaringType == typeof(MainWindowViewModel)); 


     // if any property has been updated, set isDirty to true 
     PropertyChanged += (sender, args) => 
     { 
      if (properties.Any(p => p.Name == args.PropertyName)) 
       IsDirty = true; 
     }; 

    } 

    public void Save() 
    { 
     NotifyOfPropertyChange(); 
    } 
} 

アプリケーションが実行されると、コンストラクターは名前、年齢、およびIsDirtyのプロパティーのリストを正しく生成します。ただし、Saveボタンをクリックすると、ViewModelに関連付けられていない他のプロパティのPropertyChangedEventが生成されます。IsInitializedおよびIsActiveはスクリーンのプロパティであり、リストのプロパティに対しては生成されません。誰かがここで何が起こっているのか教えてくれますか?私は、私が何をしようとしているのかがはっきりしていると思います。これは検証シナリオです。プロパティボタンをクリックしてすべてのプロパティを検証できるように、PropertyChangedを呼び出してフラグを設定する必要があります。

+0

にブレークポイントを設定します。セッターは実際に呼び出されていますか? (もしそうなら、setter *のコードを* NotifyOfPropertyChangeに進めて、そのメソッドが実際に何をしているかを確認してください...) – elgonzo

+0

いいえNotifyOfPropertyChange()は実際のセッターを呼び出しているとは思いません。 – Will

+0

もちろん、NotifyOfPropertyChangeはセッターを呼び出していません。メソッドが "RequestPropertyChange"または "ChangeProperty"ではなく "NotifyOfPropertyChange"と呼ばれていないことに注意してください...それを得ましたか?:-)だから、あなたのコードのどこにあなたのプロパティの1つのセッターですか? – elgonzo

答えて

1

NotifyOfPropertyChange()メソッドのメソッドシグネチャである:

public virtual void NotifyOfPropertyChange([System.Runtime.CompilerServices.CallerMemberName] string propertyName = null) 

(Caliburn.Micro githubのリポジトリへのリンク:https://github.com/Caliburn-Micro/Caliburn.Micro/blob/master/src/Caliburn.Micro/PropertyChangedBase.cs#L44

CallerMemberName属性は。 になりますNotifyOfPropertyChange();ようSaveメソッド内からそれを呼び出す

PropertyChangedEventArgs.PropertyNameセットに「保存」をイベントにPropertyChanged(NotifyOfPropertyChangeを呼び出すメソッドの名前())。それは当然のことではありません。あなたのクラスの任意のプロパティが変更されたことを知らせるために

は、あなたが(事実CallerMemberName置換をバイパスして)明示的にNotifyOfPropertyChangeの引数としてnullまたは""のいずれかに合格する必要があります。

public void Save() 
{ 
    NotifyOfPropertyChange(null); 
} 

nullまたは空を渡しますプロパティ名としての文字列が有効です。プロパティ名のないPropertyChangedイベントは、1つまたは複数のプロパティが値を変更したことを通知します。これを考慮

、PropertyChangedイベントハンドラは、適切にプロパティ名を指定せずにPropertyChangedイベントを尊重するとともに改善されるべきである:MainWindowViewModelで任意のプロパティのセッターに

PropertyChanged += (sender, args) => 
{ 
    if (string.IsNullOrEmpty(args.PropertyName) || properties.Any(p => p.Name == args.PropertyName)) 
     IsDirty = true; 
}; 
関連する問題