Объект привязки данных Winforms, содержащий список <T>

2

У меня проблемы с ситуацией, которая, как я знаю, должна быть довольно распространенной, поэтому я надеюсь, что решение будет простым. У меня есть объект, содержащий объекты 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
}
}
Теги:
winforms
data-binding

2 ответа

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
    Э-э-э, я опоздал на несколько секунд ;-)
  • 0
    Не забудьте реализовать INotifyPropertyChanged в классе Person. И вы должны рассмотреть возможность отменить привязку события в ListChanged, чтобы избежать утечек памяти ...
Показать ещё 2 комментария
-1

Я считаю, что вы можете искать что-то вроде этого

ITypedList

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

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

  • 0
    @joshlrogers: простите за даунвот, но это не проблема того типа данных, к которому он привязан, а привязка и уведомление не происходит правильно. ITypedList не добавляет к опыту уведомления ничего, что еще не было раскрыто INotifyPropertyChanged.
  • 0
    Хммм ..... Я перечитал вопрос и твой ответ, и я думаю, что я что-то упустил, может быть, слишком рано утром. Я предполагал, что он изменял свойство одного из объектов в одном из своих агрегатов. Другими словами, он изменял свойство Person в BindingList <Person>, поэтому он действительно не изменял коллекцию как таковую, а только объект коллекции. Поэтому, если он изменяет способ привязки сетки с помощью ITypedList, он может исключительно отслеживать изменения этих базовых свойств и уведомлять об этом. Возможно я просто не обдумываю это или не усложняю проблему.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню