我最初将DGV的数据源设置为SortableBindingList。当我运行程序时,我能够单击任何列标题并按列升序或降序排序。
我已经实现了一个Filter文本框,它使用LINQ过滤DGV中的数据。 用LINQ过滤列表后。我将过滤后的列表重新绑定到DGV,但先前排序的列不再排序。
即使重新绑定新数据源,DGV仍应继续排序吗?
我为此提出的唯一解决方法是将当前的SortedColumn索引和当前的SortOrder存储到变量中,然后在绑定新数据源时重置这些属性。
public void addFragment(Fragment fragmentToBeAdded){
Fragment topFragment = getCurrentTopFragment();
//getCurrentTopFragment returns top visible fragment using findFragmentById
if(!fragmentToBeAdded.getClass().getSimpleName()
.equals(topFragment.getClass().getSimpleName()){
//add fragmentToBeAdded
}
}
更新1 :(新密码)
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;
}
更新2 :(附加代码)
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);
}
答案 0 :(得分:2)
DataGridView
不包含自己的排序功能,而是依靠数据源来执行此操作,更具体地说是IBindingList
实现。除了排序之外,IBindingList
还提供了ListChanged
事件,可用于更新附加到其上的任何UI。请注意,IBindingList
也是一个列表,即您可以像使用普通列表一样添加/删除/更新项目,因此您不需要创建新列表并将其重新指定为数据源。相反,创建它一次,将UI附加到它,然后在任何时候只更新列表内容,UI将自动反映更改 - 数据绑定之一&#34;魔法&#34;。
现在,为了实现这一切,必须正确实施IBindingList
。 BindingList<T>
已经提供了所需的大部分功能,但不幸的是,这不包括排序。您遇到的问题源于您使用有缺陷的第三方组件(通常在没有标准组件时)。
因此,而不是MySortableBindindingList<T>
使用以下实现:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
namespace Tests
{
public class MyBindingList<T> : BindingList<T>
{
static readonly Dictionary<string, Func<IEnumerable<T>, IEnumerable<T>>> orderByMethodCache = new Dictionary<string, Func<IEnumerable<T>, IEnumerable<T>>>();
private static Func<IEnumerable<T>, IEnumerable<T>> GetOrderByMethod(PropertyDescriptor prop, ListSortDirection direction)
{
var orderByMethodName = direction == ListSortDirection.Ascending ? "OrderBy" : "OrderByDescending";
var cacheKey = typeof(T).GUID + prop.Name + orderByMethodName;
Func<IEnumerable<T>, IEnumerable<T>> orderByMethod;
if (!orderByMethodCache.TryGetValue(cacheKey, out orderByMethod))
orderByMethodCache.Add(cacheKey, orderByMethod = CreateOrderByMethod(prop, orderByMethodName));
return orderByMethod;
}
private static Func<IEnumerable<T>, IEnumerable<T>> CreateOrderByMethod(PropertyDescriptor prop, string orderByMethodName)
{
var source = Expression.Parameter(typeof(IEnumerable<T>), "source");
var item = Expression.Parameter(typeof(T), "item");
var member = Expression.Property(item, prop.Name);
var selector = Expression.Lambda(member, item);
var orderByMethod = typeof(Enumerable).GetMethods()
.Single(a => a.Name == orderByMethodName && a.GetParameters().Length == 2)
.MakeGenericMethod(typeof(T), member.Type);
var orderByExpression = Expression.Lambda<Func<IEnumerable<T>, IEnumerable<T>>>(
Expression.Call(orderByMethod, new Expression[] { source, selector }), source);
return orderByExpression.Compile();
}
List<T> originalList = new List<T>();
ListSortDirection sortDirection;
PropertyDescriptor sortProperty;
bool isSorted;
bool ignoreListChanged;
Func<T, bool> filter;
public MyBindingList() { }
public MyBindingList(IEnumerable<T> items) { Update(items); }
protected override bool SupportsSortingCore { get { return true; } }
protected override PropertyDescriptor SortPropertyCore { get { return sortProperty; } }
protected override ListSortDirection SortDirectionCore { get { return sortDirection; } }
protected override bool IsSortedCore { get { return isSorted; } }
public Func<T, bool> Filter
{
get { return filter; }
set
{
filter = value;
Refresh();
}
}
public void Update(IEnumerable<T> items)
{
originalList.Clear();
originalList.AddRange(items);
Refresh();
}
public void Refresh()
{
var items = originalList.AsEnumerable();
if (Filter != null)
items = items.Where(filter);
if (isSorted)
items = GetOrderByMethod(sortProperty, sortDirection)(items);
bool raiseListChangedEvents = RaiseListChangedEvents;
RaiseListChangedEvents = false;
base.ClearItems();
foreach (var item in items)
Add(item);
RaiseListChangedEvents = raiseListChangedEvents;
if (!raiseListChangedEvents) return;
ignoreListChanged = true;
ResetBindings();
ignoreListChanged = false;
}
protected override void OnListChanged(ListChangedEventArgs e)
{
if (!ignoreListChanged)
originalList = Items.ToList();
base.OnListChanged(e);
}
protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction)
{
var orderByMethod = GetOrderByMethod(prop, direction);
sortProperty = prop;
sortDirection = direction;
isSorted = true;
Refresh();
}
protected override void RemoveSortCore()
{
if (!isSorted) return;
isSorted = false;
Refresh();
}
}
}
还支持替换内容和用户定义的过滤器。
以下是一个如何使用它的示例,只是为了得到这个想法,但我想您可以轻松地将其映射到您的特定需求:
using System;
using System.Windows.Forms;
namespace Tests
{
class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var form = new Form();
var dg = new DataGridView { Dock = DockStyle.Fill, Parent = form };
var filterBox = new TextBox { Dock = DockStyle.Bottom, Parent = form };
var data = new MyBindingList<Person>(new[]
{
new Person { FirstName = "Jon", LastName = "Skeet" },
new Person { FirstName = "Hans", LastName = "Passant" },
new Person { FirstName = "Ivan", LastName = "Stoev" },
});
dg.DataSource = data;
var filterText = string.Empty;
filterBox.TextChanged += (sender, e) =>
{
var text = filterBox.Text.Trim();
if (filterText == text) return;
filterText = text;
if (!string.IsNullOrEmpty(filterText))
data.Filter = person => person.FirstName.Contains(filterText) || person.LastName.Contains(filterText);
else
data.Filter = null;
};
Application.Run(form);
}
}
}
答案 1 :(得分:0)
您每次都需要重新申请排序,因为您正在应用全新的数据源。
看看你是否可以适应这样的事情:
C# - code against a property using the property name as a string