2016-11-11 67 views
1

我有這個代碼,我有我的ViewModel和ViewModel有一個屬性,它獲取它的所有屬性。C#從父子觸發RaisePropertyChanged父?

這是粗糙的僞代碼:

public class MyClassViewModel : INotifyPropertyChanged 
{ 

    public MyClassViewModel() 
    { 

    } 

    public BaseClass myClassBase { get ; set; } 

    public string Title 
    { 
     get 
     { 
      return myClassBase.Title; 
     } 
     set 
     { 
      myClassBase.Title = value; 
      RaisePropertyChanged("Title"); 
     } 
    } 

    public string Description 
    { 
     get 
     { 
      return myClassBase.Description; 
     } 
     set 
     { 
      myClassBase.Description = value; 
      RaisePropertyChanged("Description"); 
     } 
    } 
} 

這是BaseClass的:

public class BaseClass 
{ 
    public BaseClass() 
    { 

    } 

    public string Title {get;set;} 
    public string Description {get;set;} 
} 

CheckItemViewModel是一個綁定到UI。所以如果我做了類似MyClassViewModel .Title =「Test」;它正確地刷新用戶界面。

但是,我需要做一些類似於MyClassViewModel.myClassBase.Title =「測試」由於特定的原因(Javascript - Chakra接口)。這樣做的問題在於UI不再刷新,因爲它沒有RaisePropertyChanged。

即使我在BaseClass本身內部實現了RaisePropertyChanged,它仍然不起作用。它不起作用,因爲BaseClass中的PropertyChanged始終爲空

我懷疑這是因爲MyClassViewModel綁定到UI。因此,BaseClass中的PropertyChanged從不綁定。

有沒有辦法觸發父母的RaisePropertyChanged?

謝謝

回答

1

我建議在這兩個類實現INotifyPropertyChanged,然後有MyClassViewModel訂閱事件BaseClass,並將其轉發到用戶界面:

public class MyClassViewModel : INotifyPropertyChanged, IDisposable 
{ 
    private BaseClass myClassBase; 

    public void Dispose() 
    { 
     if (myClassBase != null) myClassBase.PropertyChanged -= OnBaseClassPropertyChanged; 
    } 

    public BaseClass MyClassBase { 
     get { 
      return myClassBase; 
     } 

     set { 
      if (myClassBase != null) myClassBase.PropertyChanged -= OnBaseClassPropertyChanged; 
      myClassBase = value; 
      myClassBase.PropertyChanged += OnBaseClassPropertyChanged; 
     } 
    } 

    private void OnBaseClassPropertyChanged(object sender, PropertyChangedEventArgs args) { 
     RaisePropertyChanged(args.PropertyName); 
    } 

    // forwarded properties (Title and Description) go here 
} 
2

首先,可以簡化RaisePropertyChanged這樣:

public void RaisePropertyChanged([CallerMemberName] string propertyName = null) 
{ 
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
} 

所以你不需要寫RaisePropertyChanged("Description"),但只有:RaisePropertyChanged()propertyName被自動注入。如果你經常重構的真棒:你不必處理的整體解決方案:)

其次記住所有的「標題」和「描述」字符串的噩夢,如果BaseClassPropertyChangedEvent,你可以在MyClassViewModel聽它。

myClassBase.PropertyChanged += (s, e) => { RaisePropertyChanged(e.PropertyName); }; 

但是,如果你沒有在MyClassViewModel構造立即注入myClassBase,或者如果可以myClassBase改變某個時候,事情變得有點複雜。

你必須要MyClassViewModel也實現INotifyPropertyChanging

public event PropertyChangingEventHandler PropertyChanging; 

public void RaisePropertyChanging([CallerMemberName] string propertyName = null) 
{ 
    PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(propertyName)); 
} 

你也必須提高爲myClassBase通知:

public BaseClass myClassBase 
{ 
    get { return _myClassBase; } 
    set 
    { 
     RaisePropertyChanging(); 
     _myClassBase = value; 
     RaisePropertyChanged(); 
    } 
} 
private BaseClass _myClassBase; 

然後,所有你需要的是這樣的代碼:

public MyClassViewModel() 
{ 
    PropertyChanging += OnPropertyChanging; 
    PropertyChanged += OnPropertyChanged; 
} 

private void OnPropertyChanging(object sender, PropertyChangingEventArgs e) 
{ 
    if (e.PropertyName != nameof(MyClassViewModel.myClassBase)) 
     return; //or do something with the other properties 

    if (myClassBase == null) 
     return; 

    myClassBase.PropertyChanged -= OnMyBaseClassPropertyChanged; 
} 

private void OnPropertyChanged(object sender, PropertyChangedEventArgs e) 
{ 
    if (e.PropertyName != nameof(MyClassViewModel.myClassBase)) 
     return; //or do something with the other properties 

    if (myClassBase == null) 
     return; 

    myClassBase.PropertyChanged += OnMyBaseClassPropertyChanged; 
} 

private void OnMyBaseClassPropertyChanged(object sender, PropertyChangedEventArgs e) 
{ 
    RaisePropertyChanged(e.PropertyName); 
} 

注意:我使用C#-6.0 nameof()運營商,我希望你能使用它,它簡直太棒了!

編輯:

這裏有一個演示功能正常,一個簡單的測試方法:

[TestMethod] 
    public void ChildClassPropertyChanged() 
    { 
     var bc = new BaseClass(); 

     var c = new MyClassViewModel(); 

     bc.Title = "t1"; 

     c.myClassBase = bc; 

     Assert.AreEqual("t1", c.Title); 

     c.Title = "t2"; 
     Assert.AreEqual("t2", c.Title); 

     c.myClassBase.Title = "t3"; 
     Assert.AreEqual("t3", c.Title); 

     c.myClassBase = new BaseClass(); 

     bc.Title = "t4"; 
     Assert.AreEqual(null, c.Title); 

     c.myClassBase.Title = "t5"; 
     Assert.AreEqual("t5", c.Title); 
    } 

請記住,如果你設置一個nullmyClassBase,你的屬性getter和setter內該代碼將拋出一個NullReferenceException。也許你應該這樣修改它:

public string Title 
{ 
    get 
    { 
     return myClassBase?.Title; 
    } 
    set 
    { 
     if (myClassBase != null) 
       myClassBase.Title = value; 
     RaisePropertyChanged(); 
    } 
}