如何为聚合属性实现INotifyPropertyChanged

时间:2016-03-27 05:52:29

标签: c# wpf mvvm

说我有一系列订单行对象......

config.action_mailer.default_url_options = { :host => 'https://my-task-    tracker.herokuapp.com' }
config.action_mailer.delivery_method = :smtp
config.action_mailer.perform_deliveries = true
config.action_mailer.raise_delivery_errors = false
config.action_mailer.default :charset => "utf-8"
config.action_mailer.smtp_settings = {
:address              => "smtp.gmail.com",
:port                 => 587,
:user_name            => ENV["GMAIL_USERNAME"],
:password             => ENV["GMAIL_PASSWORD"],
:authentication       => "plain",
:enable_starttls_auto => true
}

我可以在public class OrderLine { public decimal Qty { get; set; } public decimal Cost { get; set; } public decimal CostExt { get { return Qty * Cost; } } } INotifyPropertyChanged中实施Qty,当这些值被修改时,我的视图会收到更新通知。但是,Cost是一个汇总值,它依赖于CostExt Qty,这意味着我被迫在其上调用Cost好吧,在它涉及的每个属性!在一个大型视图模型中,可能会有数百个属性和各种聚合物散布在一起,这将成为维护的噩梦。有没有办法强迫观点重新检查整体而没有任何不必要的痛苦?

编辑:好的,为了清楚起见,我正在寻找的设计模式将允许我简单地告诉聚合(PropertyChanged,在这种情况下)什么属性它应该考虑其约束力的组成部分。 CostExtQty以及所涉及的任何其他财产都应该不知道它们是从汇总中读取的事实。最终结果将是一个更清晰的视图模型,而不需要重写现有属性,因为新的聚合需要它们。简单,嗯?

3 个答案:

答案 0 :(得分:1)

非常简单,在其他相关属性发生更改时,在ProperttyChanged上引发CostExt事件。

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

您的(完整)实施应该像

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
}

答案 1 :(得分:1)

如果您不想手动实施INotifyPropertyChanged,请使用Fody PropertyChanged

您的代码:

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

编译时:

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

请注意,依赖于其他属性的属性将被选中。

答案 2 :(得分:0)

这样的事情怎么样:

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