订阅INotifyPropertyChanged的嵌套(子)对象

问题描述:

更新:问题解决了,请参阅my答。

UPDATE: Problem solved, see my Answer.

我在寻找一个干净和优雅解决方案来处理嵌套的(子)对象的 INotifyPropertyChanged的事件。例如:code:

I'm looking for a clean and elegant solution to handle the INotifyPropertyChanged event of nested (child) objects. Example code:

public class Person : INotifyPropertyChanged {

  private string _firstName;
  private int _age;
  private Person _bestFriend;

  public string FirstName {
    get { return _firstName; }
    set {
      // Short implementation for simplicity reasons
      _firstName = value;
      RaisePropertyChanged("FirstName");
    }
  }

  public int Age {
    get { return _age; }
    set {
      // Short implementation for simplicity reasons
      _age = value;
      RaisePropertyChanged("Age");
    }
  }

  public Person BestFriend {
    get { return _bestFriend; }
    set {
      // - Unsubscribe from _bestFriend's INotifyPropertyChanged Event
      //   if not null

      _bestFriend = value;
      RaisePropertyChanged("BestFriend");

      // - Subscribe to _bestFriend's INotifyPropertyChanged Event if not null
      // - When _bestFriend's INotifyPropertyChanged Event is fired, i'd like
      //   to have the RaisePropertyChanged("BestFriend") method invoked
      // - Also, I guess some kind of *weak* event handler is required
      //   if a Person instance i beeing destroyed
    }
  }

  // **INotifyPropertyChanged implementation**
  // Implementation of RaisePropertyChanged method

}

专注于最好的朋友属性和它的值设置器。现在的我知道我能做到这一点手动,落实在评论中描述的所有步骤。但是,这将是一个很大的code,尤其是当我打算有许多子属性实施 INotifyPropertyChanged的这样的。当然,他们不会是总是相同的类型,他们有共同的唯一的事情就是 INotifyPropertyChanged的接口。

Focus on the BestFriend Property and it's value setter. Now I know that I could do this manually, implementing all steps described in the comments. But this is going to be a lot of code, especially when I'm planning to have many child properties implementing INotifyPropertyChanged like this. Of course they are not going to be always of same Type, the only thing they have in common is the INotifyPropertyChanged interface.

的原因是,在我的现实情况下,我有一个复杂的项目(中车)对象已超过数层嵌套的对象属性(项目是有一个许可证的对象,其本身可以有子再次对象),我需要得到通知的有关项目中的任何一个变化,以便能够重新计算价格。

The reason is, that in my real scenario, I have a complex "Item" (in cart) object which has nested object properties over several layers (Item is having a "License" object, which can itself have child objects again) and I need to get notified about any single change of the "Item" to be able to recalculate the price.

你一些好的建议,甚至一些 实施帮我解决 这个?

Do you some good tips or even some implementation to help me to solve this?

不幸的是,我不能/不允许使用生成后的步骤类似PostSharp实现我的目标。

Unfortunately, I'm not able/allowed to use post-build steps like PostSharp to accomplish my goal.

非常感谢你在前进,
- 托马斯

Thank you very much in advance,
- Thomas

,因为我没能找到一个现成使用的解决方案,我已经做了基于皮特斯(和Marks)建议自定义实现(感谢!)。

since I wasn't able to find a ready-to-use solution, I've done a custom implementation based on Pieters (and Marks) suggestions (thanks!).

中的类,你会被通知在深对象树中的任何变化,这适用于任何 INotifyPropertyChanged的实施类型和 INotifyCollectionChanged *实现集合(很显然,我使用了的ObservableCollection 为)。

Using the classes, you will be notified about any change in a deep object tree, this works for any INotifyPropertyChanged implementing Types and INotifyCollectionChanged* implementing collections (Obviously, I'm using the ObservableCollection for that).

我希望这竟然是一个非常干净和优雅的解决方案,它不完全,虽然测试,有空间的改进。这是pretty的好用,只是使用它的静态创建的ChangeListener 的实例创建方法,并把你的 INotifyPropertyChanged的

I hope this turned out to be a quite clean and elegant solution, it's not fully tested though and there is room for enhancements. It's pretty easy to use, just create an instance of ChangeListener using it's static Create method and passing your INotifyPropertyChanged:

var listener = ChangeListener.Create(myViewModel);
listener.PropertyChanged += 
    new PropertyChangedEventHandler(listener_PropertyChanged);

PropertyChangedEventArgs 提供了属性名这将是永远的对​​象的完整​​路径。例如,如果你改变你的人的最好的朋友名称,在属性名将BestFriend.Name,如果最好的朋友有儿童的集合,你改变它的年龄,该值将是BestFriend.Children []。时代等。不要忘了处置当你的对象被销毁,那么它会(希望)完全从所有事件侦听器退订。

the PropertyChangedEventArgs provide a PropertyName which will be always the full "path" of your Objects. For example, if you change your Persons's "BestFriend" Name, the PropertyName will be "BestFriend.Name", if the BestFriend has a collection of Children and you change it's Age, the value will be "BestFriend.Children[].Age" and so on. Don't forget to Dispose when your object is destroyed, then it will (hopefully) completely unsubscribe from all event listeners.

它编译于.NET(经过测试,在4)和Silverlight(测试4)。因为code在分开三个等级,我已经张贴了code为 要点705450 在这里你可以抓住这一切: https://gist.github.com/705450 **

It compiles in .NET (Tested in 4) and Silverlight (Tested in 4). Because the code in seperated in three classes, I've posted the code to gist 705450 where you can grab it all: https://gist.github.com/705450 **

*),其中一个原因是,code的工作是,的ObservableCollection 也农具 INotifyPropertyChanged的,否则根据需要,将无法正常工作,这是一个已知的警告

*) One reason that the code is working is that the ObservableCollection also implements INotifyPropertyChanged, else it wouldn't work as desired, this is a known caveat

**),免费使用,在 MIT许可证

**) Use for free, released under MIT License