院長のメモ帖
2014年4月30日 水曜日
DataGridViewとBindingList<T>
.NETでデーターをいじるプログラミングをすると、DataGridViewは非常に便利なコントロールです。SQL ServerにLinqToSQLでクエリした結果をデーターバインドするだけでソート可能な表が作れるので、日常的に多用しています。
ただ、クエリ結果を演算してローカルのLinqToObjectで匿名型のIEnumerable<T>(具体的にはList<T>)に変換すると、表に表示はできますが、そのままではソートできなくなるのが不便に感じてました。DataSetやらで型情報を作ればいいのですが、せっかく匿名型で簡単にクエリーできるのに、表示のためだけに手間が多すぎて困ってました。
なんか方法があるはずだと思いながら長年ほかっておきましたが、検索したらカスタムデーターバインド(第2部)にやり方の概論が書いてありました。要するにはIBindingListインターフェースを実装するソート可能なジェネリッククラスを作ればいいということで、具体的にはBindingList<T>を継承した列挙クラスを作り、汎用ソートロジックを組み込んだIComparer<T>を継承したコンペアラークラスを作成し、IBindingListのソートメソッドをオーバーライドすればよいということでした。
サンプルソースがあったみたいなんですが、ダウンロードできず、HP上のコードは不完全なものだったので参考にしてSortableBindingList<T>を完成させました。コンストラクタでList<T>オブジェクトを受け取りIBindingListに変換し、IComparableな公開プロパティすべてを標準の序列でソートできます。IBindingListにはほかにも機能があるようですが、とりあえずソートできれば用が足りるので他の機能については実装しませんでしたが、とっても便利なクラスを作ることができました。
ただ、クエリ結果を演算してローカルのLinqToObjectで匿名型のIEnumerable<T>(具体的にはList<T>)に変換すると、表に表示はできますが、そのままではソートできなくなるのが不便に感じてました。DataSetやらで型情報を作ればいいのですが、せっかく匿名型で簡単にクエリーできるのに、表示のためだけに手間が多すぎて困ってました。
なんか方法があるはずだと思いながら長年ほかっておきましたが、検索したらカスタムデーターバインド(第2部)にやり方の概論が書いてありました。要するにはIBindingListインターフェースを実装するソート可能なジェネリッククラスを作ればいいということで、具体的にはBindingList<T>を継承した列挙クラスを作り、汎用ソートロジックを組み込んだIComparer<T>を継承したコンペアラークラスを作成し、IBindingListのソートメソッドをオーバーライドすればよいということでした。
サンプルソースがあったみたいなんですが、ダウンロードできず、HP上のコードは不完全なものだったので参考にしてSortableBindingList<T>を完成させました。コンストラクタでList<T>オブジェクトを受け取りIBindingListに変換し、IComparableな公開プロパティすべてを標準の序列でソートできます。IBindingListにはほかにも機能があるようですが、とりあえずソートできれば用が足りるので他の機能については実装しませんでしたが、とっても便利なクラスを作ることができました。
using System;
using System.Collections.Generic;
using System.Linq;
using System.ComponentModel;
using System.Data;
namespace mynamespace
{
//IBindingListのソート機能を実装したジェネリックリストクラス
public class SortableBindingList<T> : BindingList<T>
{
public static SortableBindingList<T> ToSortableBindingList(List<T> list)
{
return new SortableBindingList<T>(list);
}
public SortableBindingList(List<T> list) : base(list) { }
protected override bool SupportsSortingCore
{
get
{
return true;
}
}
protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction)
{
List<T> items = this.Items as List<T>;
if (items != null)
{
PropertyComparer<T> pc = new PropertyComparer<T>(prop, direction);
items.Sort(pc);
_isSorted = true;
}
else
_isSorted = false;
_direction = direction;
_SortProperty = prop;
this.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
}
private bool _isSorted;
protected override bool IsSortedCore
{
get { return _isSorted; }
}
private ListSortDirection _direction;
protected override ListSortDirection SortDirectionCore
{
get
{
return _direction;
}
}
private PropertyDescriptor _SortProperty;
protected override PropertyDescriptor SortPropertyCore
{
get
{
return _SortProperty;
}
}
}
//汎用コンペアラークラス
public class PropertyComparer<T> : IComparer<T>
{
public PropertyComparer(PropertyDescriptor propertyName, ListSortDirection direction)
{
this.name = propertyName;
sortDirection = (direction == ListSortDirection.Ascending) ? 1 : -1;
}
private PropertyDescriptor name;
private int sortDirection;
#region IComparer<T> メンバー
public int Compare(T x, T y)
{
IComparable left = name.GetValue(x) as IComparable;
IComparable right = name.GetValue(y) as IComparable;
int result;
if (left != null)
result = left.CompareTo(right);
else if (right == null)
result = 0;
else
result = -1;
return result * sortDirection;
}
//呼び出し用拡張メソッド
public static class BindingListExtensions
{
public static SortableBindingList<T> ToSortableBindingList<T>(this List<T> list)
{
return SortableBindingList<T>.ToSortableBindingList(list);
}
}
}
投稿者 美濃加茂市のIT獣医師 近藤 博 | コメント(1)
コメント
初めまして。
そうなんですよね。サンプル「winforms02182005_sample」がないんですよね。
そのサンプル名でググると以下のページが出てきます。
私は、それをもとにVBで仕上げました。
http://www.windows-tech.info/3/faac15e801fb186e.php
こちらに明記されている内容も参照させていただきます。
唐突に連絡を失礼しました。
ありがとうございました。
コメントする