如何让父类知道其子类的变化?
这是示例代码:
public class MyParent : INotifyPropertyChanged
{
List<MyChild> MyChildren;
public bool IsChanged
{
get
{
foreach (var child in MyChildren)
{
if (child.IsChanged) return true;
}
return false;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaiseChanged(string propName)
{
if (PropertyChanged != null)
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propName));
}
}
public class MyChild : INotifyPropertyChanged
{
private int _Value;
public int Value
{
get
{
return _Value;
}
set
{
if (_Value == value)
return;
_Value = value;
RaiseChanged("Value");
RaiseChanged("IsChanged");
}
}
private int _DefaultValue;
public int DefaultValue
{
get
{
return _DefaultValue;
}
set
{
if (_DefaultValue == value)
return;
_DefaultValue = value;
RaiseChanged("DefaultValue");
RaiseChanged("IsChanged");
}
}
public bool IsChanged
{
get
{
return (Value != DefaultValue);
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaiseChanged(string propName)
{
if (PropertyChanged != null)
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propName));
}
}
假设我现在有两个类实例,一个作为 myParent,另一个作为 myChild。 我有两个视觉元素,每个元素都有一个绑定到我的实例的 IsChnaged 属性的属性; ElementA 绑定到 myParent.IsChanged,ElementB 绑定到 myChild.IsChanged。
当 myChild.Value 与其默认值不同时,myChild.IsChanged 将设置为 true,并且 ElementB 也会相应更新。
我需要的是,当 myParent 子级中的任何一个(这里只有一个)将其 IsChanged 值设置为 true 时,其自己的(父级) IsChanged 值设置为 true 及其相应的值 元素(此处为 ElementA)相应更新。
myParent.IsChanged 仅读取一次(设置绑定时),并且对其子级更改没有任何意义。我应该将 MyParent 的 RaiseChanged("IsChanged") 放在哪里?当孩子发生变化时,如何让父母知道?
提前致谢
This is an example code:
public class MyParent : INotifyPropertyChanged
{
List<MyChild> MyChildren;
public bool IsChanged
{
get
{
foreach (var child in MyChildren)
{
if (child.IsChanged) return true;
}
return false;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaiseChanged(string propName)
{
if (PropertyChanged != null)
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propName));
}
}
public class MyChild : INotifyPropertyChanged
{
private int _Value;
public int Value
{
get
{
return _Value;
}
set
{
if (_Value == value)
return;
_Value = value;
RaiseChanged("Value");
RaiseChanged("IsChanged");
}
}
private int _DefaultValue;
public int DefaultValue
{
get
{
return _DefaultValue;
}
set
{
if (_DefaultValue == value)
return;
_DefaultValue = value;
RaiseChanged("DefaultValue");
RaiseChanged("IsChanged");
}
}
public bool IsChanged
{
get
{
return (Value != DefaultValue);
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaiseChanged(string propName)
{
if (PropertyChanged != null)
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propName));
}
}
Let's say I now have two instances of my classes, one as myParent, and the other as myChild.
I have two visual elements, that each have a property bound to the IsChnaged property of my instances; ElementA bound to myParent.IsChanged and ElementB bound to myChild.IsChanged.
When myChild.Value differs from its default value, the myChild.IsChanged is set to true and the ElementB is updated accordingly.
What I need is when either of the myParent children (which here is only one) have their IsChanged value set to true, its own (the parent's) IsChanged value be set to true and its corresponding
element (ElementA here) be updated accordingly.
The myParent.IsChanged is only read once (when the binding is set) and it has no sense about its children changing. Where should i put the RaiseChanged("IsChanged") for MyParent? How can I let the parent know when its children have changed?
Thanks in advance
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
INotifyPropertyChanged
已经为您提供了机制:PropertyChanged
事件。只需让父级向其子级的PropertyChanged
添加一个处理程序,然后在该处理程序中调用RaiseChanged("IsChanged");
另外,您可能希望将
INotifyPropertyChanged 在基类中实现,并让您的(看起来的)ViewModel 继承它。当然,这个选项不是必需的,但它会让代码更干净一些。
更新:在父对象中:
您实际上不必向子类添加任何内容,因为它在更改时已经引发了正确的事件。
INotifyPropertyChanged
has already provided the mechanism for you: thePropertyChanged
event. Just have the parent add a handler to its children'sPropertyChanged
, and then in that handler callRaiseChanged("IsChanged");
Also, you may want to put the
INotifyPropertyChanged
implementation in a base class, and have your (what appear to be) ViewModels inherit from that. Not required for this option, of course, but it will make the code a little cleaner.Update: In the parent object:
You don't actually have to add anything to the child class, since it is already raising the correct event when it changes.
进行这种通信可能很棘手,特别是当您想避免由于连接的事件处理程序而导致内存泄漏时。还有处理从集合中添加/删除的项目的情况。
我真的很喜欢 codeplex 上的 连续 LINQ 项目 的强大功能和简单性。它具有一些非常丰富的功能,用于设置“反应对象”、“连续值”和“连续集合”。这些允许您将条件定义为 Linq 表达式,然后让 CLINQ 库实时更新基础值。
在您的情况下,您可以使用 ContinuousFirstOrDefault() linq 查询设置父级,该查询监视“IsChanged == true”的任何子级。一旦子级将该值设置为 true 并引发 PropertyChanged,连续值将检测到更改并在父级中引发相应的 PropertyChanged。
好处:
代码可能如下所示:
上面的代码在构造函数中设置 ContinuousFirstOrDefault,以便它始终处于监视状态。但是,在某些情况下,您可以通过仅在调用“IsChanged”的 getter 时延迟实例化 ContinuousFirstOrDefault 来优化此操作。这样,您就不会开始监视更改,直到您知道其他一些代码确实关心更改。
Doing this kind of communication can be tricky, especially if you want to avoid memory leaks due to the event handlers that you hook up. There is also the case of handling items that are added / removed from the collection.
I've really enjoyed the power and simplicity of the Continuous LINQ project on codeplex. It has some very rich features for setting up "Reactive Objects", "Continuous Values", and "Continuous Collections". These let you define your criteria as a Linq expression and then let the CLINQ library keep the underlying values up to date in real time.
In your case, you could set up the parent with a ContinuousFirstOrDefault() linq query that watched for any child where "IsChanged == true". As soon as a child sets the value to true and raises PropertyChanged, the continuous value will detect the change and raise a corresponding PropertyChanged in the parent.
The benefits:
Here's what the code might look like:
The above code sets up the ContinuousFirstOrDefault in the constructor so that it is always monitoring. However, in some cases you can optimize this by lazily instantiating the ContinuousFirstOrDefault only when the getter for "IsChanged" is called. That way you don't start monitoring for changes until you know that some other piece of code actually cares.
您可以通过将子项存储在
ItemObservableCollection
中来自己简化事情,如 这个答案。这将允许你这样做:You can simplify things for yourself by storing your children in an
ItemObservableCollection<T>
, as discussed in this answer. That would allow you to do this:我在您的代码示例中没有看到的是父项对子项的实际引用。仅仅拥有用于通信的接口是不够的,还必须创建引用。像
myChild.parent = this;
这样的东西,然后是跨通道的事件处理程序的绑定,在子对象的“parent”属性中,它看起来像:我没有足够的上下文来为您完善此代码,但这应该会让您朝着正确的方向前进。
Something I do not see in your code sample provide is an actually reference of parent to child. It is not enough to simply have interface to communicate through, but you must also create the reference. Something like
myChild.parent = this;
followed by the binding of the event handlers across the channel, in the "parent" property of the child object it would look like:I don't have enough context to perfect this code for you but this should move you in the right direction.