简体   繁体   English

有没有办法为计算属性触发某种类型的“OnPropertyChanged”事件,该属性在集合中使用“子实体”的属性?

[英]Is there a way to trigger some kind of `OnPropertyChanged` event for a computed property that uses a property of a “child entity” in a collection?

Is there a way to trigger some kind of OnPropertyChanged event for a computed property that uses a property of a "child entity" in a collection? 有没有办法为计算属性触发某种OnPropertyChanged事件,该属性在集合中使用“子实体”的属性?

A small example: 一个小例子:

I have a simple WPF application with a DataGrid showing Customer properties. 我有一个简单的WPF应用程序,其中DataGrid显示了Customer属性。 I am using Entity Framework 5, CodeFirst approach, so I wrote my classes manually with my own INotifyPropertyChanged implementation. 我正在使用Entity Framework 5,CodeFirst方法,因此我使用自己的INotifyPropertyChanged实现手动编写了我的类。

public partial class Customer : INotifyPropertyChanged
{
    private string _firstName;
    public virtual string FirstName
    {
        get { return _firstName; }
        set
        {
            _firstName = value;
            OnPropertyChanged("FirstName");
            OnPropertyChanged("FullName");
        }
    }

    private string _lastName;
    public virtual string LastName
    {
        get { return _lastName; }
        set
        {
            _lastName = value;
            OnPropertyChanged("LastName");
            OnPropertyChanged("FullName");
        }
    }

    public virtual ICollection<Car> Cars { get; set; }
    public virtual ICollection<Invoice> Invoices { get; set; }

    ...
}

Now in that same class I created 3 computed properties: 现在在同一个类中我创建了3个计算属性:

    public string FullName
    {
        get { return (FirstName + " " + LastName).Trim(); }
    }

    public int TotalCars
    {
        get
        {
            return Cars.Count();
        }
    }

    public int TotalOpenInvoices
    {
        get
        {
            if (Invoices != null)
                return (from i in Invoices
                        where i.PayedInFull == false
                        select i).Count();
            else return 0;
        }
    }

The FullName is automatically updated in the DataGrid because I'm calling OnPropertyChanged("FullName"); FullName在DataGrid中自动更新,因为我正在调用OnPropertyChanged("FullName");

I found an example of the INotifyCollectionChanged implementation that I can probably use to auto update the TotalCars when something is added to or removed from the ICollection: http://www.dotnetfunda.com/articles/article886-change-notification-for-objects-and-collections.aspx 我找到了一个INotifyCollectionChanged实现的示例,当ICollection中添加或删除某些内容时,我可以使用它来自动更新TotalCarshttp//www.dotnetfunda.com/articles/article886-change-notification-for-objects -and-collections.aspx

But what is the best approach to trigger the OnPropertyChange("TotalOpenInvoices") when a property ( PayedInFull ) inside the ICollection ( Invoices ) changes? 但是当ICollection( Invoices )中的属性( PayedInFull )发生变化时,触发OnPropertyChange("TotalOpenInvoices")的最佳方法是什么?

Doing something like OnPropertyChanged("Customer.TotalOpenInvoices"); 做一些像OnPropertyChanged("Customer.TotalOpenInvoices"); in the Invoice class doesn't seem to do the trick... :) 在Invoice类中似乎没有诀窍...... :)

Do you have control of what goes inside your collections? 你有控制你的收藏品内容吗? If you do, you can create a Parent property on your Invoice object and when it is added to the collection, set the parent to your Customer. 如果这样做,您可以在Invoice对象上创建Parent属性,并在将其添加到集合中时,将父级设置为Customer。 Then when PaidInFull gets set, run your Customer.OnPropertyChanged("TotalOpenInvoices") or call a method on the Customer object to recalculate your invoices. 然后,当PaidInFull设置好后,运行Customer.OnPropertyChanged(“TotalOpenInvoices”)或调用Customer对象上的方法重新计算发票。

Enforcing parent-child relationship in C# and .Net 在C#和.Net中实施父子关系

This assumes that Invoice and Customer both implement IPropertyChanged. 这假设Invoice和Customer都实现了IPropertyChanged。 Simply change your collection to an ObservableCollection, and watch the CollectionChanged property. 只需将您的集合更改为ObservableCollection,并观察CollectionChanged属性。

When new Invoices are added, hook up an event handler to the PropertyChanged event of that Invoice. 添加新发票时,将事件处理程序连接到该发票的PropertyChanged事件。 When an item is removed from the collection, remove that event handler. 从集合中删除项目时,删除该事件处理程序。

Then, just call your NotifyPropertyChanged function on your TotalOpenInvoices property. 然后,只需在TotalOpenInvoices属性上调用NotifyPropertyChanged函数。

For example (not completely tested, but it should be close): 例如(未完全测试,但它应该接近):

Invoice 发票

public class Invoice : INotifyPropertyChanged
    {

        private bool payedInFull = false;
        public bool PayedInFull
        {
            get { return payedInFull; }
            set
            {
                payedInFull = value;
                NotifyPropertyChanged("PayedInFull");
            }
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion
    }

Customer 顾客

public class Customer : INotifyPropertyChanged
{
    public Customer()
    {
        this.Invoices.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Invoices_CollectionChanged);
    }

    ObservableCollection<Invoice> Invoices 
    {
        get;
        set;
    }

    public int TotalOpenInvoices
    {
        get
        {
            if (Invoices != null)
                return (from i in Invoices
                        where i.PayedInFull == false
                        select i).Count();
            else return 0;
        }
    }


    void Invoices_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        foreach (Invoice invoice in e.NewItems)
        {
            invoice.PropertyChanged += new PropertyChangedEventHandler(invoice_PropertyChanged);
            NotifyPropertyChanged("TotalOpenInvoices");
        }

        foreach (Invoice invoice in e.OldItems)
        {
            invoice.PropertyChanged -= new PropertyChangedEventHandler(invoice_PropertyChanged);
            NotifyPropertyChanged("TotalOpenInvoices");
        }
    }

    void invoice_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == "PayedInFull")
            NotifyPropertyChanged("TotalOpenInvoices");
    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion
}

Note that each class could be abstracted to a single class that implements INotifyPropertyChanged, such as a ViewModelBase class, but that is not necessarily required for this example. 请注意,每个类都可以抽象为实现INotifyPropertyChanged的单个类,例如ViewModelBase类,但这不是本示例所必需的。

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

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