2009-07-13 3 views
2

У меня проблемы с ситуацией, которая, как я знаю, должна быть довольно распространенной, поэтому я надеюсь, что решение будет простым. У меня есть объект, содержащий список объектов <>. Он также имеет некоторые свойства, которые отражают совокупные данные об объектах в списке <> (на самом деле BindingList <>, поэтому я могу привязываться к нему). В моей форме у меня есть DataGridView для List и некоторые другие поля для совокупных данных. Я не могу понять, как вызвать обновление агрегированных данных, когда значения в DataGridView будут изменены.Winforms Объект привязки данных, содержащий Список <T>

Я попытался воссоздать событие 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 
} 
} 
+0

Это похоже на http://stackoverflow.com/questions/601320/winforms-data-binding-bind-to-objects-in-a-list и может быть дубликатом. –

ответ

3

Метод 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)); 
     } 
    } 
} 

Теперь, когда свойства в элементах списка изменяется, родительский объект будет срабатывать свойство измененного события, и все, что связанно с его следует изменить, а ,

+0

Erf, gg, я был на несколько секунд слишком поздно ;-) –

+0

Не забудьте реализовать INotifyPropertyChanged в классе Person. И вы должны рассмотреть возможность отменить событие в ListChanged, чтобы избежать утечек памяти ... –

+0

@Julien Poulin: Хорошо, изменил код, чтобы отразить. Кроме того, технически это не утечка, поскольку все это будет очищено, когда экземпляр Roster будет собран (настоящая утечка никогда не будет собрана). Однако это то, что нужно сделать. – casperOne

-1

Я полагаю, вы будете искать что-то вроде этого

ITypedList

также Google Search из ITypedList отведениях вы в несколько хороших блогов о том, как реализовать.

Когда я использую ORM, я обычно должен сделать несколько из них для хорошего привязки и представления datagrid.

+0

@joshlrogers: Извините за downvote, но это не проблема типа данных, к которым привязаны, а скорее, привязки и уведомления не происходит правильно. ITypedList ничего не добавляет к опыту уведомления, который еще не был показан INotifyPropertyChanged. – casperOne

+0

Хмм ... Я перечитал вопрос и ваш ответ, и я думаю, что я просто что-то пропустил, может быть, слишком рано утром. Я предполагал, что он модифицировал свойство одного из объектов в одном из своих агрегатов. Так, другими словами, он изменял свойство Person в BindingList , поэтому он действительно не модифицировал коллекцию как таковой как объект коллекции. Поэтому, если он изменяет способ привязки сетки с помощью ITypedList, он может исключительно улавливать изменения этих базовых свойств и уведомлять. Может быть, я просто не думаю об этом или оскорбляю проблему. – joshlrogers

Смежные вопросы