依赖于其他属性的依赖属性
C类实现INotifyPropertyChanged。依赖于其他属性的依赖属性
假设C具有长度,宽度和面积属性,其中Area = Length * Width。 中的更改可能会导致面积发生更改。所有三个都是绑定的,即UI期望所有三个都通知其值的变化。
当“长度”或“宽度”更改时,它们的setter调用NotifyPropertyChanged。
我应该如何处理计算的面积属性?目前我能想到的模式是在NotifyPropertyChanged中检测更改的属性是长度还是宽度,如果是这种情况,则为Area启动一个附加的PropertyChanged通知。但是,这需要我在NotifyPropertyChanged内部维护依赖关系图,我认为这是一种反模式。
所以,我的问题是:我应该如何编码依赖于其他依赖属性的依赖属性?
编辑:这里的人认为,长和宽也呼吁NotifyPropertyChanged的区域。再次,我认为这是一种反模式。一个属性(恕我直言)不应该知道谁取决于它,因为不应该NotifyPropertyChanged。只有财产应该知道它依赖于谁。
当Length
或Width
性质改变你火PropertyChanged
为Area
除了烧制它要么Length
或Width
。
这是基于备份域和方法OnPropertyChanged
火的PropertyChanged
事件非常简单的实现:
public Double Length {
get { return this.length; }
set {
this.length = value;
OnPropertyChanged("Length");
OnPropertyChanged("Area");
}
}
public Double Width {
get { return this.width; }
set {
this.width = value;
OnPropertyChanged("Width");
OnPropertyChanged("Area");
}
}
public Double Area {
get { return this.length*this.width; }
}
做它像这样肯定是不的反模式。这正是这样做的模式。作为该课程的实施者,您知道当Length
发生变化时,Area
也会发生变化,您可以通过提高适当的事件来对其进行编码。
但如果“宽度”和“长度”是在另一个类中,那么你如何为'Area'增加'PropertyChanged'?检查这个问题的答案:http://*.com/questions/43653750/raising-propertychanged-for-a-dependent-property-when-a-prerequisite-property-in-another-class – Jogge 2017-04-28 05:26:01
虽然这是我同样如此,当你有一个中等大小的课堂时,这会很快失去控制。你开始狩猎你把你的OnPropertyChanged()调用改变的属性。当您编辑属性A时,您不应该在包含数百个,有时包含数千行代码的类文件中寻找OnPropertyChanged(“A”)调用。 – 2017-12-08 21:06:07
然后,您应该在长度和宽度属性设置器中提升两次。一个用于实际属性,另一个用于Area属性。
例如:这里
private int _width;
public int Width
{
get { return _width; }
set
{
if (_width == value) return;
_width = value;
NotifyPropertyChanged("Width");
NotifyPropertyChanged("Area");
}
}
市民提出,长度和宽度也呼吁 NotifyPropertyChanged的区域。再次,我认为这是一个反模式。一个属性(恕我直言)不应该知道谁取决于 它,因为不应该NotifyPropertyChanged。只有财产应该是 意识到它依赖于谁。
这不是反模式。实际上,你的数据封装在这个类中,所以这个类知道什么时候和什么改变了。除此之外,你不应该知道面积取决于宽度和长度。所以告知听众Area最合乎逻辑的地方是宽度和长度设置器。
的属性(恕我直言)不应该知道的谁依赖于它,因为 不应NotifyPropertyChanged。
它不会破坏封装,因为你是在同一个班级,在相同的数据结构。
额外的信息是knockout.js(一个javascript mvvm库)有一个概念,它可以访问这个问题:Computed Observables。所以我相信这是绝对可以接受的。
在Ember.js框架中,计算属性表示这个相同的功能,但它只会使计算属性声明依赖的属性名称,而不是像解决方案中所暗示的那样。 – Epirocks 2017-10-17 00:13:56
虽然它看起来很相似,但是emberjs计算属性是另一回事。通过INotifyPropertyChanged和你在这里看到的你甚至不需要声明依赖关系。 'NotifyPropertyChanged'不是像'function(){}。property('foo','bar')'这样的依赖声明,它只是触发一个事件。 – 2017-10-17 15:39:56
这就是问题所在,不是你要在一个依赖的属性中提升事件,而是隐式地声明它。看起来不正确。如果你所举的事件也依赖于对方,那该怎么办?如果B依赖于A而C依赖于B和D.对于所有人来说,属性都会调用Notify,尽管D只是模糊地关心A并且可能在语义上不相关。例如,为什么Age字段应该关注在12月4日创建的与客户有关的订单... – Epirocks 2017-10-18 16:32:06
这个问题一直困扰着我,所以我重新打开它。
首先,我想为任何考虑我个人“反模式”评论的人道歉。这里提供的解决方案实际上是如何在WPF中完成的。但是,恕我直言,它们是造成的不良做法,在其框架中存在缺陷。
我的要求是,information hiding导向决定了当B上的一个depeneds,A不应B的了解对于〔实施例,当B 从 A派生,A不应该有代码说:“如果我的运行时类型真的是B,然后做这个和那个“。 Simiarily,当B 使用 A,A应该没有代码说:“如果调用此方法的对象是B,那么......”
所以这就意味着若物业B依赖于物业A,A不该成为负责直接提醒B的人。
相反,维护(正如我目前所做的)NotifyPropertyChanged中的依赖关系图也是一种反模式。该方法应该是轻量级的,并执行它所命名的状态,而不是维护属性之间的依赖关系。
所以,我认为所需的解决方案是通过aspect oriented programming:性能B应该使用“我依赖于(属性A)”属性,并且一些代码重写器应该创建依赖关系图并透明地修改NotifyPropertyChanged。今天,我是单一产品的程序员,所以我不能证明这个问题,但我认为这是正确的解决方案。
不,你错了。信息隐藏在相同的数据结构(同一个类,没有继承)内是没有意义的。此外,INotifyPropertyChanged是一个具有一个事件的接口:PropertyChanged。谁实现这个接口,谁知道什么时候提出PropertyChanged。不需要AOP,这是一个完全不同的话题。 – 2012-02-27 15:19:33
下面是说明如何创建一个自动调用的PropertyChanged对视他人财产属性的自定义属性的文章:http://www.redmountainsw.com/wordpress/2012/01/17/a-nicer-way-to-handle-dependent-values-on-propertychanged/
的代码看起来就像这样:
[DependsOn("A")]
[DependsOn("B")]
public int Total
{
get { return A + B; }
}
public int A
{
get { return m_A; }
set { m_A = value; RaisePropertyChanged("A"); }
}
public int B
{
get { return m_B: }
set { m_B = value; RaisePropertyChanged("B"); }
}
我没试过它自己,但我喜欢这个想法
这是一个属性的可能实现:
public class DependentPropertiesAttribute : Attribute
{
private readonly string[] properties;
public DependentPropertiesAttribute(params string[] dp)
{
properties = dp;
}
public string[] Properties
{
get
{
return properties;
}
}
}
然后在基本视图模型,我们处理调用属性依赖的机制:
public class ViewModelBase : INotifyPropertyChanged
{
public ViewModelBase()
{
DetectPropertiesDependencies();
}
private readonly Dictionary<string, List<string>> _dependencies = new Dictionary<string, List<string>>();
private void DetectPropertiesDependencies()
{
var propertyInfoWithDependencies = GetType().GetProperties().Where(
prop => Attribute.IsDefined(prop, typeof(DependentPropertiesAttribute))).ToArray();
foreach (PropertyInfo propertyInfo in propertyInfoWithDependencies)
{
var ca = propertyInfo.GetCustomAttributes(false).OfType<DependentPropertiesAttribute>().Single();
if (ca.Properties != null)
{
foreach (string prop in ca.Properties)
{
if (!_dependencies.ContainsKey(prop))
{
_dependencies.Add(prop, new List<string>());
}
_dependencies[prop].Add(propertyInfo.Name);
}
}
}
}
protected void OnPropertyChanged(params Expression<Func<object>>[] expressions)
{
expressions.Select(expr => ReflectionHelper.GetPropertyName(expr)).ToList().ForEach(p => {
RaisePropertyChanged(p);
RaiseDependentProperties(p, new List<string>() { p });
});
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
protected virtual void RaisePropertyChanged(string propertyName)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
protected void RaiseDependentProperties(string propertyName, List<string> calledProperties = null)
{
if (!_dependencies.Any() || !_dependencies.ContainsKey(propertyName))
return;
if (calledProperties == null)
calledProperties = new List<string>();
List<string> dependentProperties = _dependencies[propertyName];
foreach (var dependentProperty in dependentProperties)
{
if (!calledProperties.Contains(dependentProperty))
{
RaisePropertyChanged(dependentProperty);
RaiseDependentProperties(dependentProperty, calledProperties);
}
}
}
}
最后,我们在我们的视图模型定义依赖
[DependentProperties("Prop1", "Prop2")]
public bool SomeCalculatedProperty
{
get
{
return Prop1 + Prop2;
}
}
不要混淆[依赖性](HTTP :// MSDN。microsoft.com/en-us/library/ms752914.aspx)与实现INotifyPropertyChanged的类的属性。这不是一回事。 – Clemens 2012-02-20 13:16:05
如果你真的不喜欢它。将您的视图模型注册到它自己的PropertyChanged事件中,侦听宽度和长度的属性更改,然后再次提高Area的更改。但是,它再一次证明了它可以提高多个属性。实际上,募集将永远不会调用财产的创造者,只有吸收者才是安全的。 – dowhilefor 2012-02-20 13:59:40
Duplicate http://*.com/questions/5440121/databinding-to-calculated-field – 2012-02-26 13:28:08