INotifyPropertyChanged和计算属性
假设我有一个简单的类Order,它有一个TotalPrice计算属性,可以绑定到WPF UI
public class Order : INotifyPropertyChanged { public decimal ItemPrice { get { return this.itemPrice; } set { this.itemPrice = value; this.RaisePropertyChanged("ItemPrice"); this.RaisePropertyChanged("TotalPrice"); } } public int Quantity { get { return this.quantity; } set { this.quantity= value; this.RaisePropertyChanged("Quantity"); this.RaisePropertyChanged("TotalPrice"); } } public decimal TotalPrice { get { return this.ItemPrice * this.Quantity; } } }
在影响TotalPrice计算的属性中调用RaisePropertyChanged(“TotalPrice”)是一个好习惯吗? 刷新TotalPrice属性的最佳方法是什么? 当然这样做的另一个版本是改变这样的属性
public decimal TotalPrice { get { return this.ItemPrice * this.Quantity; } protected set { if(value >= 0) throw ArgumentException("set method can be used for refresh purpose only"); } }
并调用TotalPrice = -1而不是this.RaisePropertyChanged(“TotalPrice”); 在其他属性。 请更好地提出建议
非常感谢
可以检查是否应该从可能更改值的任何其他成员中提升此事件,但只有在实际更改值时才这样做。
您可以将其封装在一个方法中:
private void CheckTotalPrice(decimal oldPrice) { if(this.TotalPrice != oldPrice) { this.RaisePropertyChanged("TotalPrice"); } }
然后你需要从你的其他变异成员那里调用它:
var oldPrice = this.TotalPrice; // mutate object here... this.CheckTotalPrice(oldPrice);
另一个解决方案是Robert Rossney在这个问题中提出的解决方案:
WPF INotifyPropertyChanged用于链接的只读属性
您可以创建属性依赖关系图(使用他的代码示例):
private static Dictionary _DependencyMap = new Dictionary { {"Foo", new[] { "Bar", "Baz" } }, };
然后在OnPropertyChanged中执行此操作:
PropertyChanged(this, new PropertyChangedEventArgs(propertyName)) if (_DependencyMap.ContainsKey(propertyName)) { foreach (string p in _DependencyMap[propertyName]) { PropertyChanged(this, new PropertyChangedEventArgs(p)) } }
您甚至可以附加属性以将依赖属性绑定到它所依赖的属性。 就像是:
[PropertyChangeDependsOn("Foo")] public int Bar { get { return Foo * Foo; } } [PropertyChangeDependsOn("Foo")] public int Baz { get { return Foo * 2; } }
我还没有实现属性的细节。 我现在最好开始研究。
如果您使用NotifyPropertyWeaver,您可以拥有此代码
public class Order : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public decimal ItemPrice { get; set; } public int Quantity { get; set; } public decimal TotalPrice { get { return ItemPrice*Quantity; } } }
它将被编译为此。
public class Order : INotifyPropertyChanged { decimal itemPrice; int quantity; public event PropertyChangedEventHandler PropertyChanged; public virtual void OnPropertyChanged(string propertyName) { var propertyChanged = PropertyChanged; if (propertyChanged != null) { propertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } public decimal ItemPrice { get { return itemPrice; } set { if (itemPrice != value) { itemPrice = value; OnPropertyChanged("TotalPrice"); OnPropertyChanged("ItemPrice"); } } } public int Quantity { get { return quantity; } set { if (quantity != value) { quantity = value; OnPropertyChanged("TotalPrice"); OnPropertyChanged("Quantity"); } } } public decimal TotalPrice { get { return ItemPrice*Quantity; } } }
在影响TotalPrice计算的属性中调用RaisePropertyChanged(“TotalPrice”)是一个好习惯吗?
不,它不是,它不规模,是一个维护噩梦。
public decimal ItemPrice { get { return Property.Get(0m); } set { Property.Set(value); } } public int Quantity { get { return Property.Get(0); } set { Property.Set(value); } } public decimal TotalPrice { get { return Property.Calculated(() => ItemPrice * Quantity); } }