10

假设我有一个简单的 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"); 在其他属性中。请提出更好的解决方案

非常感谢

4

4 回答 4

7

另一种解决方案是 Robert Rossney 在这个问题中提出的解决方案:

WPF INotifyPropertyChanged 用于链接的只读属性

您可以创建一个属性依赖映射(使用他的代码示例):

private static Dictionary<string, string[]> _DependencyMap = 
new Dictionary<string, string[]>
{
   {"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; } }

我还没有实现属性的细节。我最好现在就着手处理。

于 2011-01-04T17:46:27.560 回答
4

可以检查一下您是否也应该从可能更改值的任何其他成员那里引发此事件,但只有在您实际更改值时才这样做。

您可以将其封装在一个方法中:

private void CheckTotalPrice(decimal oldPrice)
{
    if(this.TotalPrice != oldPrice)
    {
         this.RaisePropertyChanged("TotalPrice");
    }
}

然后你需要从你的其他变异成员那里调用它:

var oldPrice = this.TotalPrice;
// mutate object here...
this.CheckTotalPrice(oldPrice);
于 2010-02-10T10:09:24.583 回答
4

在影响 TotalPrice 计算的属性中调用 RaisePropertyChanged("TotalPrice") 是一种好习惯吗?

不,它不是,它不能扩展并且(财产应该知道一切依赖它的事实)是维护的噩梦

https://github.com/StephenCleary/CalculatedProperties是迄今为止 MVVM 的最佳公式引擎(在我看来),它通知派生/计算属性的变化并支持任何级别的嵌套,最重要的是依赖树可以跨越多个对象,并且可以在运行时动态更改。

  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); }    
  }

这与 Excel 公式非常相似,但适用于 MVVM。ItemPrice 和 Quantity 不知道什么依赖于它们,也不关心为依赖的 TotalPrice 提高 PropertyChanged。依赖关系树可以根据需要具有多个级别。

于 2017-11-08T00:59:30.593 回答
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; }
    }
}
于 2012-02-05T09:39:36.930 回答