2017-06-02 82 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; 
};