2017-06-02 262 views
0

我有一个简单的WPF应用程序,我想知道为什么NotifyOfPropertyChange()没有按照我的预期工作。我有一个MainWindowViewModel有两个属性和一个按钮,当我点击按钮时,我调用NotifyOfPropertyChange()来通知所有属性已经改变。我也有在视图模型构造编译的属性列表: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(); 
    } 
} 

当应用程序运行时,构造函数正确地生成属性列表:Name,Age和IsDirty。但是,单击“保存”按钮时,会为与视图模型不相关的其他属性引发PropertyChangedEvent:IsInitialized和IsActive(它们是屏幕的属性),并且不会为列表中的任何属性引发PropertyChangedEvent。有人能告诉我这里发生了什么,或者给出一个替代解决方案吗?我想它很清楚我想要做什么,这是一个验证场景,我需要调用一个PropertyChanged并设置一个标志(如果单击保存按钮),以便可以验证所有属性。

+0

设置断点:

考虑到这一点,PropertyChanged事件处理程序也应该被提高到适当尊重的PropertyChanged事件,而属性名。这些设置者实际上是否被调用? (如果是的话,继续通过setter *的代码进入* NotifyOfPropertyChange,看看这个方法真的在做什么...) – elgonzo

+0

不,我不相信NotifyOfPropertyChange()调用实际的setter。 – Will

+0

那么,NotifyOfPropertyChange当然不会调用setter。请注意,该方法不称为“RequestPropertyChange”或“ChangeProperty”,而是“NotifyOfPropertyChange”...明白了吗?:-)那么,你的代码中的哪个地方是你的一个属性的setter? – 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属性。

Save方法类似NotifyOfPropertyChange();内调用它会导致的PropertyChanged事件与PropertyChangedEventArgs.PropertyName设置为“保存”(该方法的调用NotifyOfPropertyChange名称())。这当然没有意义。

要通知,在你的类中的任何属性发生变化时,你必须明确地通过其中null""作为论据NotifyOfPropertyChange(有效地绕过CallerMemberName替代):

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

传递null或空字符串作为属性名称是有效的。没有属性名称的PropertyChanged事件表示任何一个或多个属性已更改其值。在MainWindowViewModel任何属性的制定者

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