【发布时间】:2015-10-14 18:32:30
【问题描述】:
我最初将 DGV 的数据源设置为 SortableBindingList。当我运行程序时,我可以单击任何列标题并按列升序或降序排序。
我已经实现了一个过滤器文本框,它使用 LINQ 过滤 DGV 中的数据。 在我用 LINQ 过滤列表之后。我将过滤后的列表重新绑定到 DGV,但之前排序的列不再排序。
即使在我重新绑定新数据源后,DGV 是否应该继续排序?
为此我想出的唯一解决方法是将当前的 SortedColumn 索引和当前的 SortOrder 存储到变量中,然后在绑定新数据源时重置这些属性。
private void PopulateGrid()
{
var gridSource = new MySortableBindingList<Case>(_caseList);
dataGridView_Cases.DataSource = gridSource;
ConfigureGrid();
}
private void ApplyFilter(string fString)
{
MySortableBindingList<Case> msbList = new MySortableBindingList<Case>(_caseList.Where(x => (x.StudentLastName.IndexOf(fString, StringComparison.OrdinalIgnoreCase) >= 0) || (x.StudentIDDisplay.ToString().IndexOf(fString, StringComparison.OrdinalIgnoreCase) >= 0)).ToList());
dataGridView_Cases.DataSource = msbList;
}
更新 1:(新代码)
private MySortableBindingList<Case> _gridSource = new MySortableBindingList<Case>();
BindingSource _caseBindingSource = new BindingSource();
private void PopulateGrid()
{
_gridSource = new MySortableBindingList<Case>(_caseList);
_caseBindingSource.DataSource = _gridSource;
dataGridView_Cases.DataSource = _caseBindingSource;
ConfigureGrid();
}
private void ApplyFilter(string fString)
{
_gridSource.Clear();
foreach (var fCase in _caseList.Where(x => (x.StudentLastName.IndexOf(fString, StringComparison.OrdinalIgnoreCase) >= 0) || (x.StudentIDDisplay.ToString().IndexOf(fString, StringComparison.OrdinalIgnoreCase) >= 0)).ToList())
{
_gridSource.Add(fCase);
}
_caseBindingSource.ResetBindings(false);
}
更新 2:(附加代码)
/// <summary>
/// Source: http://www.codeproject.com/Articles/31418/Implementing-a-Sortable-BindingList-Very-Very-Quic
/// </summary>
/// <typeparam name="T"></typeparam>
public class MySortableBindingList<T> : BindingList<T>
{
// reference to the list provided at the time of instantiation
List<T> originalList;
ListSortDirection sortDirection;
PropertyDescriptor sortProperty;
// function that refereshes the contents
// of the base classes collection of elements
Action<MySortableBindingList<T>, List<T>>
populateBaseList = (a, b) => a.ResetItems(b);
// a cache of functions that perform the sorting
// for a given type, property, and sort direction
static Dictionary<string, Func<List<T>, IEnumerable<T>>>
cachedOrderByExpressions = new Dictionary<string, Func<List<T>,
IEnumerable<T>>>();
/// <summary>
/// Create a sortable binding list
/// </summary>
public MySortableBindingList()
{
originalList = new List<T>();
}
/// <summary>
/// Create a sortable binding list
/// </summary>
public MySortableBindingList(IEnumerable<T> enumerable)
{
originalList = enumerable.ToList();
populateBaseList(this, originalList);
}
/// <summary>
/// Create a sortable binding list
/// </summary>
public MySortableBindingList(List<T> list)
{
originalList = list;
populateBaseList(this, originalList);
}
/// <summary>
/// Look for an appropriate sort method in the cache if not found .
/// Call CreateOrderByMethod to create one.
/// Apply it to the original list.
/// Notify any bound controls that the sort has been applied.
/// </summary>
/// <param name="prop"></param>
/// <param name="direction"></param>
protected override void ApplySortCore(PropertyDescriptor prop,
ListSortDirection direction)
{
/*
Look for an appropriate sort method in the cache if not found .
Call CreateOrderByMethod to create one.
Apply it to the original list.
Notify any bound controls that the sort has been applied.
*/
sortProperty = prop;
var orderByMethodName = sortDirection ==
ListSortDirection.Ascending ? "OrderBy" : "OrderByDescending";
var cacheKey = typeof(T).GUID + prop.Name + orderByMethodName;
if (!cachedOrderByExpressions.ContainsKey(cacheKey))
{
CreateOrderByMethod(prop, orderByMethodName, cacheKey);
}
ResetItems(cachedOrderByExpressions[cacheKey](originalList).ToList());
ResetBindings();
sortDirection = sortDirection == ListSortDirection.Ascending ?
ListSortDirection.Descending : ListSortDirection.Ascending;
}
private void CreateOrderByMethod(PropertyDescriptor prop,
string orderByMethodName, string cacheKey)
{
/*
Create a generic method implementation for IEnumerable<T>.
Cache it.
*/
var sourceParameter = Expression.Parameter(typeof(List<T>), "source");
var lambdaParameter = Expression.Parameter(typeof(T), "lambdaParameter");
var accesedMember = typeof(T).GetProperty(prop.Name);
var propertySelectorLambda =
Expression.Lambda(Expression.MakeMemberAccess(lambdaParameter,
accesedMember), lambdaParameter);
var orderByMethod = typeof(Enumerable).GetMethods()
.Where(a => a.Name == orderByMethodName &&
a.GetParameters().Length == 2)
.Single()
.MakeGenericMethod(typeof(T), prop.PropertyType);
var orderByExpression = Expression.Lambda<Func<List<T>, IEnumerable<T>>>(
Expression.Call(orderByMethod,
new Expression[] { sourceParameter,
propertySelectorLambda }),
sourceParameter);
cachedOrderByExpressions.Add(cacheKey, orderByExpression.Compile());
}
/// <summary>
/// RemoveSortCore
/// </summary>
protected override void RemoveSortCore()
{
ResetItems(originalList);
}
private void ResetItems(List<T> items)
{
base.ClearItems();
for (int i = 0; i < items.Count; i++)
{
base.InsertItem(i, items[i]);
}
}
/// <summary>
/// SupportsSortingCore
/// </summary>
protected override bool SupportsSortingCore
{
get
{
// indeed we do
return true;
}
}
/// <summary>
/// Ascending or descending
/// </summary>
protected override ListSortDirection SortDirectionCore
{
get
{
return sortDirection;
}
}
/// <summary>
/// A property
/// </summary>
protected override PropertyDescriptor SortPropertyCore
{
get
{
return sortProperty;
}
}
/// <summary>
/// List has changed
/// </summary>
/// <param name="e"></param>
protected override void OnListChanged(ListChangedEventArgs e)
{
originalList = base.Items.ToList();
}
}
【问题讨论】:
-
在更改
DataSources之间不会保留排序顺序是有道理的;考虑新的DataSource没有旧DataSource的所有列(读取:已排序的列)的情况。我相信将它们存储在变量中并以编程方式重新分配排序数据是唯一的方法。 -
为什么总是重新分配数据源?分配一次,然后修改内容并引发 Reset 事件。
-
@IvanStoev 绑定为数据源后如何修改内容?什么重置事件?
-
@IvanStoev 调用 ResetBindings() 方法不会使 datagridview 刷新数据源。似乎重新分配数据源仍然是让 datagridview 更新为最新数据的唯一方法
标签: c# winforms sorting datagridview