Есть ли способ вызвать какое-то событие OnPropertyChanged для вычисляемого свойства, которое использует свойство "дочерней сущности" в коллекции?
Есть ли способ вызвать какой-то OnPropertyChanged
событие для вычисляемого свойства, которое использует свойство "дочерней сущности" в коллекции?
Небольшой пример:
У меня есть простое приложение WPF с DataGrid, показывающим свойства клиента. Я использую 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; }
...
}
Теперь в этом же классе я создал 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;
}
}
FullName
автоматически обновляется в DataGrid, потому что я звоню OnPropertyChanged("FullName");
Я нашел пример реализации INotifyCollectionChanged, которую я, вероятно, могу использовать для автоматического обновления TotalCars
когда что-то добавляется или удаляется из коллекции ICollection: http://www.dotnetfunda.com/articles/article886-change-notification-for-objects-and-collections.aspx
Но что является лучшим подходом для запуска OnPropertyChange("TotalOpenInvoices")
когда собственность (PayedInFull
внутри коллекции ICollection (Invoices
) изменения?
Делать что-то вроде OnPropertyChanged("Customer.TotalOpenInvoices");
в классе Invoice, кажется, не добиваются цели...:)
2 ответа
У вас есть контроль над тем, что происходит внутри ваших коллекций? Если вы это сделаете, вы можете создать родительское свойство для своего объекта Invoice, и когда оно будет добавлено в коллекцию, установите родительское значение для вашего Customer. Затем, когда PaidInFull будет установлен, запустите ваш Customer.OnPropertyChanged("TotalOpenInvoices") или вызовите метод объекта Customer для пересчета ваших счетов.
Это предполагает, что Invoice и Customer оба реализуют IPropertyChanged. Просто измените свою коллекцию на ObservableCollection и просмотрите свойство CollectionChanged.
При добавлении новых счетов-фактур подключите обработчик событий к событию PropertyChanged этого счета-фактуры. Когда элемент удаляется из коллекции, удалите этот обработчик событий.
Затем просто вызовите функцию NotifyPropertyChanged в свойстве TotalOpenInvoices.
Например (не полностью проверено, но должно быть близко):
Счет-фактура
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
}
Покупатель
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
}
Обратите внимание, что каждый класс может быть абстрагирован до одного класса, который реализует INotifyPropertyChanged, такого как класс ViewModelBase, но это не обязательно требуется для этого примера.