简体   繁体   English

如何为聚合属性实现 INotifyPropertyChanged

[英]How to implement INotifyPropertyChanged for aggregate properties

Say I have a collection of order line objects...假设我有一组订单行对象...

public class OrderLine {
    public decimal Qty { get; set; }
    public decimal Cost { get; set; }
    public decimal CostExt { 
       get {
           return Qty * Cost;
       }
    }
}

I can implement INotifyPropertyChanged in Qty and Cost when those values are modified, and my view will be notified of the update.当这些值被修改时,我可以在QtyCost实现INotifyPropertyChanged ,并且我的视图将收到更新通知。 However, CostExt is an aggregate value, it relies on both Qty and Cost , meaning that I am forced to invoke PropertyChanged on it as well, in each property that it relates to!然而, CostExt是一个聚合值,它依赖于QtyCost ,这意味着我也被迫在它相关的每个属性中调用PropertyChanged In a large view-model with potentially hundreds of properties and various aggregates sprinkled throughout, this would become a nightmare to maintain.在一个可能有数百个属性和各种聚合体的大型视图模型中,这将成为维护的噩梦。 Is there a way to coerce the view to re-examine the aggregate without any undue suffering?有没有办法强迫见地重新审视总体而没有任何过度的痛苦?

Edit : OK, just to be clear, the design pattern I'm looking for will allow me to simply tell the aggregate( CostExt , in this case) what properties it should consider integral to its binding.编辑:好的,只是要清楚,我正在寻找的设计模式将允许我简单地告诉聚合(在本例中为CostExt )它应该考虑哪些属性是其绑定的组成部分。 Qty , Cost , and any other property involved should need to know nothing about the fact that they are being read from by the aggregate. QtyCost和任何其他涉及的属性应该不需要知道它们正在被聚合读取的事实。 The end result will be a much cleaner view-model without the need to rewrite existing properties because a new aggregate requires them.最终结果将是一个更清晰的视图模型,而无需重写现有属性,因为新的聚合需要它们。 Simple, eh?很简单吧?

Very simple, Raise ProperttyChanged event on CostExt when ever other dependent properties are changed.非常简单,当其他相关属性发生更改时,在CostExtCostExt ProperttyChanged事件。

   public decimal Qty
    {
        get { return _qty; }
        set
        {
            _qty = value; 
            OnPropertyChanged("Qty");
            OnPropertyChanged("CostExt");
        }
    }

Your (complete)implementation should be like您的(完整)实现应该是这样的

public class OrderLine : INotifyPropertyChanged
{
    private decimal _qty;
    private decimal _cost;

    public decimal Qty
    {
        get { return _qty; }
        set
        {
            _qty = value; 
            OnPropertyChanged("Qty");
            OnPropertyChanged("CostExt");
        }
    }

    public decimal Cost
    {
        get { return _cost; }
        set
        {
            _cost = value;
            OnPropertyChanged("Cost");
            OnPropertyChanged("CostExt");
        }
    }

    public decimal CostExt
    {
        get
        {
            return Qty * Cost;
        }
    }

    #region Implementation of INotifyPropertyChanged

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion
}

If you don't want to manually implement INotifyPropertyChanged, use Fody PropertyChanged .如果您不想手动实现 INotifyPropertyChanged,请使用Fody PropertyChanged

Your code:您的代码:

[ImplementPropertyChanged]
public class Person 
{        
    public string GivenNames { get; set; }
    public string FamilyName { get; set; }

    public string FullName
    {
        get
        {
            return string.Format("{0} {1}", GivenNames, FamilyName);
        }
    }
}

When compiled:编译时:

public class Person : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    string givenNames;
    public string GivenNames
    {
        get { return givenNames; }
        set
        {
            if (value != givenNames)
            {
                givenNames = value;
                OnPropertyChanged("GivenNames");
                OnPropertyChanged("FullName");
            }
        }
    }

    string familyName;
    public string FamilyName
    {
        get { return familyName; }
        set 
        {
            if (value != familyName)
            {
                familyName = value;
                OnPropertyChanged("FamilyName");
                OnPropertyChanged("FullName");
            }
        }
    }

    public string FullName
    {
        get
        {
            return string.Format("{0} {1}", GivenNames, FamilyName);
        }
    }

    public virtual void OnPropertyChanged(string propertyName)
    {
        var propertyChanged = PropertyChanged;
        if (propertyChanged != null)
        {
            propertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Notice that properties that depends on other properties will get picked up.请注意,依赖于其他属性的属性将被选取。

How about something like this:这样的事情怎么样:

public class OrderLine : INotifyPropertyChanged {

    decimal qty;
    decimal cost;

    public decimal Qty {
        get { return qty; }
        set { SetNotify(ref qty, value, "Qty", "CostExt"); }
    }

    public decimal Cost {
        get { return cost; }
        set { SetNotify(ref cost, value, "Cost", "CostExt"); }
    }

    public decimal CostExt {
        get {
            return Qty * Cost;
        }
    }

    protected void SetNotify<T>(ref T property, T value, params string[] notificationProperties) {
        var method = PropertyChanged;
        if (method != null) {
            foreach (var p in notificationProperties) {
                method(this, new PropertyChangedEventArgs(p));
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM