前回の記事 では、カスタムデータを利用して DataGridView を表示する方法をまとめましたが、 今回はその続きで DataGridView で カスタムデータ を ソート可能にする 方法 を見ていきます。
目次
概要
DataGridView で ソート可能 にすることは簡単で、
以下に載せる SortableBindingList を DataGridView.DataSource へ設定するだけです。
なんのひねりもないのでサクッとサンプルコードを見ていきましょう。
ソート可能なバインディングリスト
何と言ってもこのソースコードが必要! これさえあればカスタムデータも DataGridView でソートできる! そんな魔法のようなリストオブジェクトのサンプルコードを以下に載せます。
SortableBindingList.cs
namespace Sample
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
/// <summary>
/// ソート可能なバインディングリストクラス
/// </summary>
/// <typeparam name="T">リスト内容</typeparam>
public class SortableBindingList<T> : BindingList<T>
where T : class
{
/// <summary>
/// ソート済みかどうか
/// </summary>
private bool isSorted;
/// <summary>
/// 並べ替え操作の方向
/// </summary>
private ListSortDirection sortDirection = ListSortDirection.Ascending;
/// <summary>
/// ソートを行う抽象化プロパティ
/// </summary>
private PropertyDescriptor sortProperty;
/// <summary>
/// SortableBindingList クラス の 新しいインスタンス を初期化します。
/// </summary>
public SortableBindingList()
{
}
/// <summary>
/// 指定した リストクラス を利用して SortableBindingList クラス の 新しいインスタンス を初期化します。
/// </summary>
/// <param name="list">SortableBindingList に格納される System.Collection.Generic.IList</param>
public SortableBindingList(IList<T> list)
: base(list)
{
}
/// <summary>
/// リストがソートをサポートしているかどうかを示す値を取得します。
/// </summary>
protected override bool SupportsSortingCore
{
get { return true; }
}
/// <summary>
/// リストがソートされたかどうかを示す値を取得します。
/// </summary>
protected override bool IsSortedCore
{
get { return this.isSorted; }
}
/// <summary>
/// ソートされたリストの並べ替え操作の方向を取得します。
/// </summary>
protected override ListSortDirection SortDirectionCore
{
get { return this.sortDirection; }
}
/// <summary>
/// ソートに利用する抽象化プロパティを取得します。
/// </summary>
protected override PropertyDescriptor SortPropertyCore
{
get { return this.sortProperty; }
}
/// <summary>
/// ApplySortCore で適用されたソートに関する情報を削除します。
/// </summary>
protected override void RemoveSortCore()
{
this.sortDirection = ListSortDirection.Ascending;
this.sortProperty = null;
this.isSorted = false;
}
/// <summary>
/// 指定されたプロパティおよび方向でソートを行います。
/// </summary>
/// <param name="prop">抽象化プロパティ</param>
/// <param name="direction">並べ替え操作の方向</param>
protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction)
{
// ソートに使う情報を記録
this.sortProperty = prop;
this.sortDirection = direction;
// ソートを行うリストを取得
var list = Items as List<T>;
if (list == null)
{
return;
}
// ソート処理
list.Sort(this.Compare);
// ソート完了を記録
this.isSorted = true;
// ListChanged イベントを発生させます
this.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
}
/// <summary>
/// 比較処理を行います。
/// </summary>
/// <param name="lhs">左側の値</param>
/// <param name="rhs">右側の値</param>
/// <returns>比較結果</returns>
private int Compare(T lhs, T rhs)
{
// 比較を行う
var result = this.OnComparison(lhs, rhs);
// 昇順の場合 そのまま、降順の場合 反転させる
return (this.sortDirection == ListSortDirection.Ascending) ? result : -result;
}
/// <summary>
/// 昇順として比較処理を行います。
/// </summary>
/// <param name="lhs">左側の値</param>
/// <param name="rhs">右側の値</param>
/// <returns>比較結果</returns>
private int OnComparison(T lhs, T rhs)
{
object lhsValue = (lhs == null) ? null : this.sortProperty.GetValue(lhs);
object rhsValue = (rhs == null) ? null : this.sortProperty.GetValue(rhs);
if (lhsValue == null)
{
return (rhsValue == null) ? 0 : -1;
}
if (rhsValue == null)
{
return 1;
}
if (lhsValue is IComparable)
{
return ((IComparable)lhsValue).CompareTo(rhsValue);
}
if (lhsValue.Equals(rhsValue))
{
return 0;
}
return lhsValue.ToString().CompareTo(rhsValue.ToString());
}
}
}
実装サンプル
フォームには dataGridView1 という DataGridView が配置されている前提で SortableBindingList の使用例を以下に載せます。
Form1.cs
public partial class Form1 : Form
{
public Form1()
{
this.InitializeComponent();
var list = new SortableBindingList<UserModel>()
{
new UserModel()
{
Id = "0010",
FirstName = "Kurihara",
LastName = "Yuki",
Email = "yuki.kurihara@gmail.com",
Password = "*****"
},
new UserModel()
{
Id = "0020",
FirstName = "Momotsuki",
LastName = "Shinya",
Email = "shinya.momotsuki@gmail.com",
Password = "*****"
}
};
this.dataGridView1.DataSource = list;
}
}
ソートできない状態にする場合は BindingSource を挟んで DataGridView.DataSource へリストを設定していましたが、
SortableBindingList を利用する場合はそのまま DataGridView.DataSource へリストを設定できます。
これを実行すると、以下のようにカラムタイトルを選択してソートできるようになり、ソート方向を示す三角アイコンが表示されるようになります。
参考記事
最後に… このブログに興味を持っていただけた方は、 ぜひ 「Facebookページ に いいね!」または 「Twitter の フォロー」 お願いします!!
