Bài viết MS do Daok đề xuất giúp tôi đi đúng hướng, nhưng tôi không hài lòng với việc triển khai SortableSearchableList của MS. Tôi thấy rằng việc thực hiện rất lạ và nó không hoạt động tốt khi có các giá trị trùng lặp trong một cột.Nó cũng không ghi đè IsSortedCore, mà dường như được yêu cầu bởi DataGridView. Nếu IsSortedCore không được overriden, glyph tìm kiếm không xuất hiện và toggling giữa tăng dần và giảm dần không hoạt động.
Xem phiên bản SortableSearchableList của tôi bên dưới. Trong ApplySortCore() nó sắp xếp bằng cách sử dụng một delegate Compare được đặt thành một phương thức nặc danh. Phiên bản này cũng hỗ trợ thiết lập các so sánh tùy chỉnh cho một thuộc tính cụ thể, có thể được thêm vào bởi một lớp dẫn xuất sử dụng AddCustomCompare().
Tôi không chắc chắn nếu thông báo bản quyền vẫn được áp dụng, nhưng tôi vừa mới rời khỏi nó trong.
//---------------------------------------------------------------------
// Copyright (C) Microsoft Corporation. All rights reserved.
//
//THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY
//KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
//IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
//PARTICULAR PURPOSE.
//---------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using System.Collections;
namespace SomethingSomething
{
/// <summary>
/// Supports sorting of list in data grid view.
/// </summary>
/// <typeparam name="T">Type of object to be displayed in data grid view.</typeparam>
public class SortableSearchableList<T> : BindingList<T>
{
#region Data Members
private ListSortDirection _sortDirectionValue;
private PropertyDescriptor _sortPropertyValue = null;
/// <summary>
/// Dictionary from property name to custom comparison function.
/// </summary>
private Dictionary<string, Comparison<T>> _customComparisons = new Dictionary<string, Comparison<T>>();
#endregion
#region Constructors
/// <summary>
/// Default constructor.
/// </summary>
public SortableSearchableList()
{
}
#endregion
#region Properties
/// <summary>
/// Indicates if sorting is supported.
/// </summary>
protected override bool SupportsSortingCore
{
get
{
return true;
}
}
/// <summary>
/// Indicates if list is sorted.
/// </summary>
protected override bool IsSortedCore
{
get
{
return _sortPropertyValue != null;
}
}
/// <summary>
/// Indicates which property the list is sorted.
/// </summary>
protected override PropertyDescriptor SortPropertyCore
{
get
{
return _sortPropertyValue;
}
}
/// <summary>
/// Indicates in which direction the list is sorted on.
/// </summary>
protected override ListSortDirection SortDirectionCore
{
get
{
return _sortDirectionValue;
}
}
#endregion
#region Methods
/// <summary>
/// Add custom compare method for property.
/// </summary>
/// <param name="propertyName"></param>
/// <param name="compareProperty"></param>
protected void AddCustomCompare(string propertyName, Comparison<T> comparison)
{
_customComparisons.Add(propertyName, comparison);
}
/// <summary>
/// Apply sort.
/// </summary>
/// <param name="prop"></param>
/// <param name="direction"></param>
protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction)
{
Comparison<T> comparison;
if (!_customComparisons.TryGetValue(prop.Name, out comparison))
{
// Check to see if the property type we are sorting by implements
// the IComparable interface.
Type interfaceType = prop.PropertyType.GetInterface("IComparable");
if (interfaceType != null)
{
comparison = delegate(T t1, T t2)
{
IComparable val1 = (IComparable)prop.GetValue(t1);
IComparable val2 = (IComparable)prop.GetValue(t2);
return val1.CompareTo(val2);
};
}
else
{
// Last option: convert to string and compare.
comparison = delegate(T t1, T t2)
{
string val1 = prop.GetValue(t1).ToString();
string val2 = prop.GetValue(t2).ToString();
return val1.CompareTo(val2);
};
}
}
if (comparison != null)
{
// If so, set the SortPropertyValue and SortDirectionValue.
_sortPropertyValue = prop;
_sortDirectionValue = direction;
// Create sorted list.
List<T> _sortedList = new List<T>(this);
_sortedList.Sort(comparison);
// Reverse order if needed.
if (direction == ListSortDirection.Descending)
{
_sortedList.Reverse();
}
// Update list.
int count = this.Count;
for (int i = 0; i < count; i++)
{
this[i] = _sortedList[i];
}
// Raise the ListChanged event so bound controls refresh their
// values.
OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
}
}
// Method below was in the original implementation from MS. Don't know what it's for.
// -- Martijn Boeker, Jan 21, 2010
//protected override void RemoveSortCore()
//{
// //int position;
// //object temp;
// //// Ensure the list has been sorted.
// //if (unsortedItems != null)
// //{
// // // Loop through the unsorted items and reorder the
// // // list per the unsorted list.
// // for (int i = 0; i < unsortedItems.Count;)
// // {
// // position = this.Find(SortPropertyCore.Name,
// // unsortedItems[i].GetType().
// // GetProperty(SortPropertyCore.Name).
// // GetValue(unsortedItems[i], null));
// // if (position >= 0 && position != i)
// // {
// // temp = this[i];
// // this[i] = this[position];
// // this[position] = (T)temp;
// // i++;
// // }
// // else if (position == i)
// // i++;
// // else
// // // If an item in the unsorted list no longer exists, delete it.
// // unsortedItems.RemoveAt(i);
// // }
// // OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
// //}
//}
/// <summary>
/// Ability to search an item.
/// </summary>
protected override bool SupportsSearchingCore
{
get
{
return true;
}
}
/// <summary>
/// Finds an item in the list.
/// </summary>
/// <param name="prop"></param>
/// <param name="key"></param>
/// <returns></returns>
protected override int FindCore(PropertyDescriptor prop, object key)
{
// Implementation not changed from MS example code.
// Get the property info for the specified property.
PropertyInfo propInfo = typeof(T).GetProperty(prop.Name);
T item;
if (key != null)
{
// Loop through the the items to see if the key
// value matches the property value.
for (int i = 0; i < Count; ++i)
{
item = (T)Items[i];
if (propInfo.GetValue(item, null).Equals(key))
return i;
}
}
return -1;
}
/// <summary>
/// Finds an item in the list.
/// </summary>
/// <param name="prop"></param>
/// <param name="key"></param>
/// <returns></returns>
private int Find(string property, object key)
{
// Implementation not changed from MS example code.
// Check the properties for a property with the specified name.
PropertyDescriptorCollection properties =
TypeDescriptor.GetProperties(typeof(T));
PropertyDescriptor prop = properties.Find(property, true);
// If there is not a match, return -1 otherwise pass search to
// FindCore method.
if (prop == null)
return -1;
else
return FindCore(prop, key);
}
#endregion
}
}
Nguồn
2010-01-22 07:30:32
BindingListView thuận tiện có sẵn thông qua NuGet: Cài đặt-Package Unofficial.BindingListView – user1016736