У меня проблемы с ситуацией, которая, как я знаю, должна быть довольно распространенной, поэтому я надеюсь, что решение будет простым. У меня есть объект, содержащий объекты List < > . Он также имеет некоторые свойства, которые отражают совокупные данные об объектах в List < > (фактически BindingList < > , поэтому я могу привязываться к нему). В моей форме у меня есть DataGridView для List и некоторые другие поля для совокупных данных. Я не могу понять, как вызвать обновление агрегированных данных, когда значения в DataGridView будут изменены.
Я попытался создать событие PropertyChanged, когда свойства объектов в Списке изменены, но, похоже, не обновляет отображение агрегированных данных. Если я получаю доступ к агрегированному свойству (например, отображать его в окне сообщений), текстовое поле в основной форме обновляется.
Вот несколько упрощенных кодов для иллюстрации того, что я пытаюсь сделать:
namespace WindowsFormsApplication1 {
public class Person {
public int Age {
get;
set;
}
public String Name {
get;
set;
}
}
public class Roster : INotifyPropertyChanged {
public BindingList<Person> People {
get;
set;
}
public Roster () {
People = new BindingList<Person>();
}
private int totalage;
public int TotalAge {
get {
calcAges();
return totalage;
}
set {
totalage = value;
NotifyPropertyChanged("TotalAge");
}
}
private void calcAges () {
int total = 0;
foreach ( Person p in People ) {
total += p.Age;
}
TotalAge = total;
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged ( String info ) {
if ( PropertyChanged != null ) {
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
#endregion
}
}
Метод calcAges
и свойство TotalAge
выглядят очень подозрительными.
Во-первых, TotalAge
должен быть доступен только для чтения. Если вы позволите ему быть общедоступной и доступной для записи, какова логика изменения компонентов, составляющих возраст?
Во-вторых, каждый раз, когда вы получаете значение, вы запускаете событие PropertyChanged
, что не очень хорошо.
Ваш класс Roster
должен выглядеть следующим образом:
public class Roster : INotifyPropertyChanged {
public Roster ()
{
// Set the binding list, this triggers the appropriate
// event binding which would be gotten if the BindingList
// was set on assignment.
People = new BindingList<Person>();
}
// The list of people.
BindingList<Person> people = null;
public BindingList<Person> People
{
get
{
return people;
}
set
{
// If there is a list, then remove the delegate.
if (people != null)
{
// Remove the delegate.
people.ListChanged -= OnListChanged;
}
/* Perform error check here */
people = value;
// Bind to the ListChangedEvent.
// Use lambda syntax if LINQ is available.
people.ListChanged += OnListChanged;
// Technically, the People property changed, so that
// property changed event should be fired.
NotifyPropertyChanged("People");
// Calculate the total age now, since the
// whole list was reassigned.
CalculateTotalAge();
}
}
private void OnListChanged(object sender, ListChangedEventArgs e)
{
// Just calculate the total age.
CalculateTotalAge();
}
private void CalculateTotalAge()
{
// Store the old total age.
int oldTotalAge = totalage;
// If you can use LINQ, change this to:
// totalage = people.Sum(p => p.Age);
// Set the total age to 0.
totalage = 0;
// Sum.
foreach (Person p in People) {
totalage += p.Age;
}
// If the total age has changed, then fire the event.
if (totalage != oldTotalAge)
{
// Fire the property notify changed event.
NotifyPropertyChanged("TotalAge");
}
}
private int totalage = 0;
public int TotalAge
{
get
{
return totalage;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged ( String info ) {
if ( PropertyChanged != null ) {
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
Теперь, когда свойства в элементах списка изменены, родительский объект упустит событие с измененным свойством, и все связанное с ним также должно измениться.
Я считаю, что вы можете искать что-то вроде этого
Кроме того, Google Search в ITypedList приводит вас к нескольким приятным блогам о том, как реализовать.
Когда я использую ORM, я обычно должен сделать несколько из них для хорошего привязки и представления datagrid.