1

BindingListにデータバインドされたDataGridViewがあります。私の DataGridView には、追加したカスタム列もいくつかあります。これらはデータ バインドではなく、BindingList のアイテムに基づいて生成されます (つまり、タイプ A の BindingList のアイテムにはタイプ B のプロパティがあります。カスタム列には B.Name が表示されます (編集:この場合、" Name" はクラス B のプロパティであるため、列によって表されるプロパティは BindingList 内の項目には直接見つかりません))。

DataGridView のすべての列を並べ替えることができる必要があります。DataGridView には、Sort(IComparer) と Sort(DataGridViewColumn, ListSortDirection) の 2 つの並べ替えメソッドがあります。2 番目のものを使用してデータ バインドされた列を並べ替えますが、もちろん、データ バインドされていない列で使用すると例外がスローされます。DataSource が null でない場合、最初のメソッドは例外をスローします。

したがって、私が知る限り、DataGridView の組み込みの Sort メソッドはどちらも機能しません。カスタム列に基づいてグリッドを並べ替えるには、他にどのような方法がありますか?

編集:

現時点で行っていることは、次の手順に従って、列ヘッダーのクリックを処理することです: http://msdn.microsoft.com/en-us/library/system.windows.forms.datagridview.columnheadermouseclick.aspx

問題は次の行で発生します。

dataGridView1.Sort(newColumn, direction);

newColumn が BindingList 内のオブジェクトのプロパティの 1 つを保持している場合、うまく機能します。しかし、カスタム列の 1 つを並べ替えるには、この行を完全に回避し、その列に基づいてデータ グリッドを並べ替える別の方法を見つける必要があります。それは、独自のソート機能を構築する必要があるということですか? とてつもない痛みになりそうです。

4

1 に答える 1

1

最終編集/回答: DataGridView に組み込まれている並べ替えメカニズムを使用しながら、これを行う方法は考えられません。私があなたの立場なら、おそらく各列の SortMode を「Programmatic」に変更してから、「ColumnHeaderMouseClick」を自分で処理するでしょう。その時点で、変更された BindingList クラスでソート メソッドを呼び出す必要があります。このメソッドは、クリックされた列に従って必要に応じてソートを実行します。これにより、DGV の Sort メソッドの使用が回避され、基になるリストが直接並べ替えられます。

完全な談話はコメントセクションにあります。元の回答はすぐに続きます:

編集:問題に関する混乱とその後の議論のため、この回答のコメントに新しい提案があります。参照できるように、投稿した元の回答を残します。

私は最近これをしなければなりませんでした - そして私はそれが本当に苦痛だったと嘘をつきません. 私は解決策を思いつきました(ここSOの友人の助けを借りて)ので、ここに行きます。列と方向の両方を指定できる新しい IComparer ベースのインターフェイスを作成しました。これを行ったのは、ソート コードをできるだけ汎用にする必要があるためです。このようにソートする必要がある 2 つのグリッドがあり、2 倍のコードを維持したくありません。非常にシンプルなインターフェースは次のとおりです。

   public interface IByColumnComparer : IComparer
   {
      string SortColumn { get; set; }
      bool SortDescending { get; set; }
   }

明らかに、一般的なものを維持することを心配していない場合 (おそらくそうするべきです)、これは厳密には必要ありません。次に、BindingList<> に基づく新しいクラスを作成しました。これにより、並べ替えコードをオーバーライドし、列ごとに独自の IByColumnComparer を提供できるようになりました。これにより、必要な柔軟性が得られました。これをチェックしてください:

public class SortableGenericCollection<T> : BindingList<T>
{
  IByColumnComparer GenericComparer = null; 

  public SortableGenericCollection(IByColumnComparer SortingComparer)
  {
     GenericComparer = SortingComparer;
  }


  protected override bool SupportsSortingCore
  {
     get
     {
        return true;
     }
  }

  protected override bool IsSortedCore
  {
     get
     {
        for (int i = 0; i < Items.Count - 1; ++i)
        {
           T lhs = Items[i];
           T rhs = Items[i + 1];
           PropertyDescriptor property = SortPropertyCore;
           if (property != null)
           {
              object lhsValue = lhs == null ? null :
              property.GetValue(lhs);
              object rhsValue = rhs == null ? null :
              property.GetValue(rhs);
              int result;
              if (lhsValue == null)
              {
                 result = -1;
              }
              else if (rhsValue == null)
              {
                 result = 1;
              }
              else
              {
                 result = GenericComparer.Compare(lhs, rhs); 
              }
              if (result >= 0)
              {
                 return false;
              }
           }
        }
        return true;
     }
  }

  private ListSortDirection sortDirection;
  protected override ListSortDirection SortDirectionCore
  {
     get
     {
        return sortDirection;
     }
  }

  private PropertyDescriptor sortProperty;
  protected override PropertyDescriptor SortPropertyCore
  {
     get
     {
        return sortProperty;
     }
  }

  protected override void ApplySortCore(PropertyDescriptor prop,
  ListSortDirection direction)
  {
     sortProperty = prop;
     sortDirection = direction;

     GenericComparer.SortColumn = prop.Name;
     GenericComparer.SortDescending = direction == ListSortDirection.Descending ? true : false;

     List<T> list = (List<T>)Items;
     list.Sort(delegate(T lhs, T rhs)
     {
        if (sortProperty != null)
        {
           object lhsValue = lhs == null ? null :
           sortProperty.GetValue(lhs);
           object rhsValue = rhs == null ? null :
           sortProperty.GetValue(rhs);
           int result;
           if (lhsValue == null)
           {
              result = -1;
           }
           else if (rhsValue == null)
           {
              result = 1;
           }
           else
           {
              result = GenericComparer.Compare(lhs, rhs);
           }
           return result;
        }
        else
        {
           return 0;
        }
     });
  }

  protected override void RemoveSortCore()
  {
     sortDirection = ListSortDirection.Ascending;
     sortProperty = null;
  }
}

今、ApplySortCore メソッドでわかるように、列と方向を DataGridView から直接受け取っています。つまり、これをプログラムで呼び出していないということです。これはやりたいことのようには思えませんが、プログラムで呼び出して適切な IByColumnComparer を渡す必要がある場合は、このコードを簡単に変更できます。このすべてをお見せする私のポイントは、ソート アルゴリズムを変更する方法を理解できるようにすることです。これは非常に便利です。

このクラスをより一般的にすることに関する提案について、@MartinhoFernandes に感謝します。

于 2011-05-16T18:14:13.433 に答える