2016-11-11 9 views
1

У меня есть этот код, где у меня есть моя ViewModel, и у ViewModel есть свойство, где он получает все свои свойства.C# Trigger RaisePropertyChanged of Parent от ребенка?

Это грубый псевдокод:

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 = "Test" по определенным причинам (Javascript - интерфейс Chakra). Проблема заключается в том, что пользовательский интерфейс не обновляется, так как он не имеет RaisePropertyChanged.

Даже когда я внедрил RaisePropertyChanged внутри BaseClass сам по себе он по-прежнему не работает. Это не работает, потому что Свойство: Изменено в BaseClass всегда равно.

Я подозреваю, что это связано с тем, что MyClassViewModel привязан к пользовательскому интерфейсу. Так что PropertyChanged в BaseClass никогда не привязан.

Есть ли способ вызвать Parise's 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 автоматически вводится. Это замечательно, если вы реорганизовывать часто: вы не должны иметь дело с кошмара вспомнить все «Title» и «Описание» строки в целом решение :)

Во-вторых, если BaseClass имеет PropertyChangedEvent, вы можете послушайте его в MyClassViewModel.

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

Но, если вы не вводить myClassBase сразу в конструкторе MyClassViewModel, или если 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); 
} 

NB: Я использую C# -6.0 nameof(), надеюсь, вы можете использовать его, это просто потрясающе!

EDIT:

Здесь у вас есть простой метод тестирования, который демонстрирует правильную функциональность:

[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, внутри добытчиками и сеттеров вашей недвижимости код выдает NullReferenceException. Возможно, вам следует изменить его следующим образом:

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

 Смежные вопросы

  • Нет связанных вопросов^_^