SortableBindingList
ソート用のバインディングリストです。
第2キーを設定したい場合には以下のように使用します。
↓↓↓↓↓↓↓↓↓↓↓↓
/// <summary>
第2キーを設定したい場合には以下のように使用します。
// Nameがソートされる際はIdでソートするようにソート方法変更
var idCompare = new Dictionary<string, IComparer<Data>>
{
{"Name", ComparerUtils.By((Data r) => r.Id)}
};
//ソートの条件
var sortCompare = ComparerUtils.By((Data r) => r.Date).Append(ComparerUtils.By((Data r) => r.Name));
// 検索データの設定
this.dgvList.DataSource = null;
this.dgvList.DataSource = new SortableBindingList<Data>(filterList, sortCompare);
↓↓↓↓↓↓↓↓↓↓↓↓
/// <summary>
/// ソート用の拡張バインディングリスト
/// </summary>
/// <typeparam name="T"></typeparam>
public class SortableBindingList<T> :BindingList<T>
{
/// <summary>
/// ソート項目
/// </summary>
private PropertyDescriptor _sortProp;
/// <summary>
/// ソート方向(昇順・降順)の保持を行います。
/// </summary>
private ListSortDirection _sortDir = ListSortDirection.Ascending;
/// <summary>
/// ソート済みかを示す値
/// </summary>
private bool _isSorted;
/// <summary>
/// 最優先比較オブジェクト
/// </summary>
private readonly Dictionary<string, IComparer<T>> _prioritySort;
/// <summary>
/// 第2キーの追加比較オブジェクト
/// </summary>
private readonly IComparer<T> _baseComparer;
/// <summary>
/// コンストラクタ
/// </summary>
public SortableBindingList()
{
}
/// <summary>
/// コンストラクタ
/// </summary>
public SortableBindingList(IList<T> list)
: this(list,null)
{
}
/// <summary>
/// コンストラクタ
/// </summary>
public SortableBindingList(IList<T> list,IComparer<T> baseComparer)
: this(list, baseComparer,null)
{
_baseComparer = baseComparer;
}
/// <summary>
/// コンストラクタ
/// </summary>
public SortableBindingList(IList<T> list, IComparer<T> baseComparer, Dictionary<string, IComparer<T>> prioritySort)
: base(list)
{
_baseComparer = baseComparer;
_prioritySort = prioritySort;
}
public void ResetSort()
{
_sortProp = null;
_sortDir = ListSortDirection.Ascending;
_isSorted = false;
}
/// <summary>
/// ソート処理
/// </summary>
/// <param name="property">ソート項目</param>
/// <param name="direction">ソート方向</param>
protected override void ApplySortCore(PropertyDescriptor property, ListSortDirection direction)
{
var list = this.Items as List<T>;
if (list != null)
{
// 比較処理を実行します。
IComparer<T> compare;
if (_prioritySort != null && _prioritySort.ContainsKey(property.DisplayName))
{
// 比較オブジェクトの取得
compare = direction == ListSortDirection.Ascending ? _prioritySort[property.DisplayName] : _prioritySort[property.DisplayName].Reverse();
}
else
{
// 比較オブジェクト作成
compare = PropertyComparerFactory.Factory<T>(property, direction);
}
// 比較処理を実行します。
list.Sort(_baseComparer == null ? compare : compare.Append(_baseComparer));
// ソート処理の終了を設定
this._isSorted = true;
this._sortProp = property;
this._sortDir = direction;
this.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
}
}
/// <summary>
/// ソートのサポートを行う事を宣言
/// </summary>
protected override bool SupportsSortingCore
{
get { return true; }
}
/// <summary>
/// 削除処理用
/// </summary>
protected override void RemoveSortCore()
{
}
/// <summary>
/// ソート済みかを示す値の取得用
/// </summary>
protected override bool IsSortedCore
{
get { return this._isSorted; }
}
/// <summary>
/// ソート対象
/// </summary>
protected override PropertyDescriptor SortPropertyCore
{
get { return this._sortProp; }
}
/// <summary>
/// ソート方向(昇順・降順)の保持を行います。
/// </summary>
protected override ListSortDirection SortDirectionCore
{
get { return this._sortDir; }
}
}
/// <summary>
/// ソート用のクラス
/// </summary>
public static class PropertyComparerFactory
{
public static IComparer<T> Factory<T>(PropertyDescriptor property, ListSortDirection direction)
{
var seed = typeof(PropertyComparer<,>);
Type[] typeArgs = { typeof(T), property.PropertyType };
var pcType = seed.MakeGenericType(typeArgs);
var comparer = (IComparer<T>)Activator.CreateInstance(pcType, new object[] { property, direction });
return comparer;
}
}
/// <summary>
/// 比較クラス
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="U"></typeparam>
public sealed class PropertyComparer<T, U> : IComparer<T>
{
private readonly PropertyDescriptor _property;
private readonly ListSortDirection _direction;
private readonly Comparer<U> _comparer;
public PropertyComparer(PropertyDescriptor property, ListSortDirection direction)
{
this._property = property;
this._direction = direction;
this._comparer = Comparer<U>.Default;
}
public int Compare(T x, T y)
{
var xValue = (U)this._property.GetValue(x);
var yValue = (U)this._property.GetValue(y);
if (this._direction == ListSortDirection.Ascending)
return this._comparer.Compare(xValue, yValue);
else
return this._comparer.Compare(yValue, xValue);
}
}
/// <summary>
/// IComparer[T]補助関数
/// </summary>
public static class ComparerUtils
{
/// <summary>
/// 動的にデリゲートから生成するIComparer[T]実装
/// </summary>
/// <typeparam name="T">比較対象の型</typeparam>
private sealed class DynamicComparer<T> : IComparer<T>
{
private readonly Func<T, T, int> _compare;
/// <summary>
/// 2 つのオブジェクトを比較し、一方が他方より小さいか、等しいか、大きいかを示す値を返します。
/// </summary>
/// <param name="x">比較する最初のオブジェクトです。</param>
/// <param name="y">比較する 2 番目のオブジェクト。</param>
/// <returns>
/// x と y の相対的な値を示す符号付き整数 (次の表を参照)。
/// 値 : 説明
/// number < 0 : x が y より小さい。
/// 0 : x と y は等しい。
/// 0 より大 : x が y より大きい。
/// </returns>
public int Compare(T x, T y)
{
return _compare(x, y);
}
/// <summary>
/// コンストラクタ
/// </summary>
/// <param name="compare">比較関数</param>
public DynamicComparer(Func<T, T, int> compare)
{
this._compare = compare;
}
}
/// <summary>
/// 比較するキーを指定してComparerを生成します。
/// </summary>
/// <typeparam name="T">比較対象の型</typeparam>
/// <typeparam name="TP">キーの型</typeparam>
/// <param name="selector">比較対象からキーを取得する関数</param>
/// <param name="comparer">キーのComparer</param>
/// <returns>Comparer</returns>
public static IComparer<T> By<T, TP>(Func<T, TP> selector, IComparer<TP> comparer)
{
return new DynamicComparer<T>((x, y) => comparer.Compare(selector(x), selector(y)));
}
/// <summary>
/// 比較するキーを指定してComparerを生成します。比較にはComparer[TP].Defaultを使用します
/// </summary>
/// <typeparam name="T">比較対象の型</typeparam>
/// <typeparam name="TP">キーの型</typeparam>
/// <param name="selector">比較対象からキーを取得する関数</param>
/// <returns>Comparer</returns>
public static IComparer<T> By<T, TP>(Func<T, TP> selector)
where TP : IComparable<TP>
{
return By(selector, Comparer<TP>.Default);
}
/// <summary>
/// Comparerでの比較結果が同一だった場合に、第二引数のComparerで比較を行うようなComparerを生成します
/// </summary>
/// <typeparam name="T">比較対象の型</typeparam>
/// <param name="comparer">優先する第一のComparer</param>
/// <param name="second">第二のComparer</param>
/// <returns>Comparer</returns>
public static IComparer<T> Append<T>(this IComparer<T> comparer, IComparer<T> second)
{
return new DynamicComparer<T>((x, y) =>
{
var first = comparer.Compare(x, y);
if (first != 0)
{
return first;
}
return second.Compare(x, y);
});
}
/// <summary>
/// Comparerの比較順序を逆転させます
/// </summary>
/// <typeparam name="T">比較対象の型</typeparam>
/// <param name="comparer">元となるComparer</param>
/// <returns>Comparer</returns>
public static IComparer<T> Reverse<T>(this IComparer<T> comparer)
{
return new DynamicComparer<T>((x, y) => comparer.Compare(y, x));
}
}