为嵌套(子)对象订阅 INotifyPropertyChanged [英] Subscribe to INotifyPropertyChanged for nested (child) objects
问题描述
我正在寻找一种干净且优雅的解决方案来处理嵌套(子)对象的 INotifyPropertyChanged
事件.示例代码:
public class Person : INotifyPropertyChanged {私人字符串_firstName;私人 int _age;私人人_bestFriend;公共字符串名字{得到 { 返回 _firstName;}放 {//为简单起见的简短实现_firstName = 值;RaisePropertyChanged("名字");}}公共整数年龄{得到{返回_年龄;}放 {//为简单起见的简短实现_年龄=价值;RaisePropertyChanged("年龄");}}公众人物最好的朋友{得到 { 返回 _bestFriend;}放 {//- 取消订阅 _bestFriend 的 INotifyPropertyChanged 事件//如果不为空_bestFriend = 价值;RaisePropertyChanged("BestFriend");//- 如果不为空,则订阅 _bestFriend 的 INotifyPropertyChanged 事件//- 当 _bestFriend 的 INotifyPropertyChanged 事件被触发时,我想要//调用 RaisePropertyChanged("BestFriend") 方法//- 另外,我猜需要某种 *weak* 事件处理程序//如果我正在销毁一个 Person 实例}}//**INotifyPropertyChanged 实现**//RaisePropertyChanged 方法的实现}
关注 BestFriend
属性及其值设置器.现在我知道我可以手动执行此操作,执行评论中描述的所有步骤.但这将是大量代码,尤其是当我计划让许多子属性像这样实现 INotifyPropertyChanged
时.当然,它们不会总是相同的类型,它们唯一的共同点是 INotifyPropertyChanged
接口.
原因是,在我的真实场景中,我有一个复杂的Item"(在购物车中)对象,它在多个层上嵌套了对象属性(Item 有一个License"对象,它本身又可以有子对象) 并且我需要收到有关项目"的任何单一更改的通知,以便能够重新计算价格.
你有什么好的建议吗?实现帮我解决这是?
不幸的是,我不能/不允许使用 PostSharp 等构建后步骤来实现我的目标.
由于我无法找到现成的解决方案,我已经根据 Pieters(和 Marks)的建议进行了自定义实现(谢谢!).
使用这些类,您将收到有关深层对象树中任何更改的通知,这适用于任何 INotifyPropertyChanged
实现类型和 INotifyCollectionChanged
* 实现集合(显然,我'正在使用 ObservableCollection
.
我希望这是一个非常干净和优雅的解决方案,虽然它没有经过全面测试,但仍有改进的空间.它非常易于使用,只需使用它的静态 Create
方法创建一个 ChangeListener
实例并传递您的 INotifyPropertyChanged
:
var listener = ChangeListener.Create(myViewModel);listener.PropertyChanged +=新的 PropertyChangedEventHandler(listener_PropertyChanged);
PropertyChangedEventArgs
提供了一个 PropertyName
,它将始终是您的对象的完整路径".例如,如果您更改 Persons 的BestFriend"名称,则 PropertyName
将是BestFriend.Name",如果 BestFriend
有一个 Children 的集合并且您更改了它的 Age,该值将为BestFriend.Children[].Age"等.不要忘记在您的对象被销毁时Dispose
,然后它会(希望)完全取消订阅所有事件侦听器.
它在 .NET(在 4 中测试)和 Silverlight(在 4 中测试)中编译.因为代码分为三类,我把代码贴到gist 705450strong> 在这里您可以获取所有内容:https://gist.github.com/705450 **
*) 代码正常工作的一个原因是 ObservableCollection
也实现了 INotifyPropertyChanged
,否则它不会按预期工作,这是一个已知的警告>
**) 免费使用,根据 MIT 许可
发布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
}
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?
Unfortunately, I'm not able/allowed to use post-build steps like PostSharp to accomplish my goal.
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!).
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).
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);
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.
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 **
*) 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
**) Use for free, released under MIT License
这篇关于为嵌套(子)对象订阅 INotifyPropertyChanged的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!