2009-07-13 9 views
2

私はよく知っている必要がある状況に問題がありますので、解決策が簡単であると思っています。オブジェクトのリスト<を含むオブジェクトがあります。また、リスト<>(実際にバインディングリスト<>にバインドできるので、オブジェクトの集計データを反映するいくつかのプロパティもあります)。私のフォームでは、List用のDataGridViewと、集計データ用のいくつかのフィールドがあります。 DataGridViewの値が変更されたときに、集計データの更新をトリガーする方法を理解できません。Winformsリストを含むデータバインディングオブジェクト<T>

Listのオブジェクトのプロパティが変更されたときに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は読み取り専用にする必要があります。それを公開して書き込み可能にする場合、年齢を構成するコンポーネントを変更するロジックは何ですか?

第2に、値を取得するたびに、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

PersonクラスにINotifyPropertyChangedを実装するのを忘れないでください。そして、メモリリークを避けるためにListChangedでイベントをバインド解除することを検討する必要があります... –

+0

@Julien Poulin:良い点、反映するコードを変更しました。また、技術的には、Rosterインスタンスが収集されたときにすべてがクリーンアップされるため、漏れではありません(実際の漏れは決して収集されません)。しかし、それはすべきことです。 – casperOne

-1

私はあなたがまた、この

ITypedList

ITypedListリードのGoogle Searchのようなものを探している可能性がありと信じて実装する方法については、いくつかの素晴らしいブログを参照してください。

私がORMを使用するとき、私は通常、素敵なデータグリッドのバインドとプレゼンテーションのためにこれらのいくつかを行う必要があります。

+0

@joshlrogers:downvoteは申し訳ありませんが、これはバインドされているデータのタイプの問題ではなく、バインディングと通知が正しく行われていません。 ITypedListは、INotifyPropertyChangedによって公開されていない通知エクスペリエンスに何も追加しません。 – casperOne

+0

ええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええ、私は彼が彼の集合体の1つのオブジェクトの1つのプロパティを変更していたと仮定していました。つまり、彼はBindingList のPersonのプロパティを変更していたので、実際にコレクション自体をコレクションのオブジェクトに変更していないのです。したがって、ITypedListを使用してグリッドをバインドする方法を変更した場合、それらのプロパティの変更を排他的にキャッチして通知することができます。たぶん私はそれを考えていない、あるいは問題を複雑にしているだけではない。 – joshlrogers

関連する問題