INotifyPropertyChanged и вычисляемое свойство - PullRequest
7 голосов
/ 10 февраля 2010

Предположим, у меня есть простой класс Order, у которого есть вычисляемое свойство TotalPrice, которое может быть связано с пользовательским интерфейсом WPF

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

Рекомендуется ли вызывать RaisePropertyChanged ("TotalPrice") в свойствах, которые влияют на вычисление 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 вместо этого. RaisePropertyChanged ("TotalPrice"); в других свойствах. пожалуйста, предложите решения лучше

Большое спасибо

Ответы [ 4 ]

7 голосов
/ 04 января 2011

Другое решение, предложенное Робертом Росни в этом вопросе:

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

Я еще не реализовал детали атрибута.Я бы лучше занялся этим сейчас.

4 голосов
/ 10 февраля 2010

Хорошо проверить, стоит ли вам вызывать это событие также и от любого другого члена, который может изменить значение, но только если вы действительно измените значение.

Вы можете заключить это в метод:

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

Тогда вам нужно позвонить другим членам-мутаторам:

var oldPrice = this.TotalPrice;
// mutate object here...
this.CheckTotalPrice(oldPrice);
2 голосов
/ 08 ноября 2017

Полезно ли вызывать RaisePropertyChanged ("TotalPrice") в свойствах, которые влияют на вычисление 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 и Количество не знают, что от них зависит, и не заботятся о повышении PropertyChanged для зависимого TotalPrice. Дерево зависимостей может иметь столько уровней, сколько необходимо.

2 голосов
/ 05 февраля 2012

Если вы используете 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; }
    }
}
...