使所有数据网格视图列可排序
本文关键字:视图 排序 网格 数据网 数据 | 更新日期: 2023-09-27 18:31:36
>我有一个带有datagridview
的Windows表单。
理想情况:
用户单击九列中的任何一列,程序对所有数据进行排序,如果单击的列包含数字,我希望顶部的最低数字。如果单击的列包含字符串,我希望它按字母顺序(A-Z)排序。
我现在有什么:
我在堆栈溢出上看到了一个旧问题,其中OP在单击"a"标题时如何对数据网格视图进行排序。与我的区别在于,我希望我的数据网格视图可以按九列中的任何一列进行排序。
我有这个代码,是从我发现的问题中窃取的:
dataGridView2.DataSource = listPlayers.Select(s => new { voornaam = s.Voornaam,
Achternaam = s.Achternaam,
positie = s.Positie,
Nationaltieit = s.Nationaliteit,
Leeftijd = s.Age,
Aanval = s.Aanval,
Verdediging = s.Verdediging,
Gemiddeld = s.Gemiddeld,
waarde = s.TransferWaarde })
.OrderBy(s => s.Achternaam)
.ToList();
foreach(DataGridViewColumn column in dataGridView2.Columns)
{
dataGridView2.Columns[column.Name].SortMode =
DataGridViewColumnSortMode.Automatic;
}
这仅允许用户在单击九列之一时按"Achternaam"排序。我想要的是当用户单击Nationaliteit列时,数据将按顶部的An进行排序。以此类推,每一列
这是列表玩家列表:
namespace SimulatorSimulator
{
class SpelerData
{
public string Voornaam { get; set; }
public string Achternaam { get; set; }
public string Positie { get; set; }
public string Nationaliteit { get; set; }
public int Age { get; set; }
public int Aanval { get; set; }
public int Verdediging { get; set; }
public int Gemiddeld { get; set; }
public string TransferWaarde { get; set; }
}
}
在主类中:
List<SpelerData> listPlayers = new List<SpelerData>();
一些虚拟数据:
Romelu;Lukaku;Aanvaller;Belgie;22;87;12;50;41.000.000,00
Raheem ;Sterling;Aanvaller;Engeland;21;84;30;57;35.000.000,00
Zlatan ;Ibrahimovic;Aanvaller;Zweden;34;87;21;54;34.500.000,00
我确实认为最简单的方法是将数据放在Database
表中。这样,您可以简单地将其用作dataGridView2
的data source
,并且您可以通过单击标题列轻松进行排序。
另一种方法是使用SortableBindingList(文章),因为另一个答案也建议了。
但是,如果这两个选项都不在您的选择之列,我能想到的下一个最简单的方法是从ColumnHeaderMouseClick
创建事件,然后您可以通过使用e.ColumnIndex
和正确的"映射"(字典)来相应地列出您的排序到您准备好的IEnumerable<SpelerData>
因此,在表单加载中,您可以执行以下操作:
Dictionary<int, IEnumerable<SpelerData>> queryDict = new Dictionary<int, IEnumerable<SpelerData>>(); //Prepare a dictionary of query
private void form_load(object sender, EventArgs e) {
dataGridView2.DataSource = listPlayers.OrderBy(x => x.Achternaam).ToList();
queryDict.Add(0, listPlayers.OrderBy(x => x.Voornaam));
queryDict.Add(1, listPlayers.OrderBy(x => x.Achternaam));
queryDict.Add(2, listPlayers.OrderBy(x => x.Positie));
queryDict.Add(3, listPlayers.OrderBy(x => x.Nationaliteit));
queryDict.Add(4, listPlayers.OrderBy(x => x.Age));
queryDict.Add(5, listPlayers.OrderBy(x => x.Aanval));
queryDict.Add(6, listPlayers.OrderBy(x => x.Verdediging));
queryDict.Add(7, listPlayers.OrderBy(x => x.Gemiddeld));
queryDict.Add(8, listPlayers.OrderBy(x => x.TransferWaarde));
}
然后在ColumnHeaderMouseClick
事件中,只需执行以下操作:
private void dataGridView2_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e) {
dataGridView2.DataSource = queryDict[e.ColumnIndex].ToList();
}
你会得到你想要的行为。
请注意,由于IEnumerable
是延迟执行的,因此提前准备Dictionary
根本不会对性能产生影响。您唯一需要添加的是form_Load中用于准备字典的 9 行代码和 dataGridView2_ColumnHeaderMouseClick
事件中的 1 行代码。除了我之前提到的两个我能想到的最简单的解决方案。
您可以使用 SortableBindingList
SortableBindingList<T> list = new SortableBindingList<T>();
//Add items to list
dataGridView.DataSource = list ;
这将允许在单击列标题时进行排序
public class SortableBindingList<T> : BindingList<T>
{
private readonly Dictionary<Type, PropertyComparer<T>> comparers;
private bool isSorted;
private ListSortDirection listSortDirection;
private PropertyDescriptor propertyDescriptor;
public SortableBindingList()
: base(new List<T>())
{
this.comparers = new Dictionary<Type, PropertyComparer<T>>();
}
public SortableBindingList(IEnumerable<T> enumeration)
: base(new List<T>(enumeration))
{
this.comparers = new Dictionary<Type, PropertyComparer<T>>();
}
protected override bool SupportsSortingCore
{
get { return true; }
}
protected override bool IsSortedCore
{
get { return this.isSorted; }
}
protected override PropertyDescriptor SortPropertyCore
{
get { return this.propertyDescriptor; }
}
protected override ListSortDirection SortDirectionCore
{
get { return this.listSortDirection; }
}
protected override bool SupportsSearchingCore
{
get { return true; }
}
protected override void ApplySortCore(PropertyDescriptor property, ListSortDirection direction)
{
List<T> itemsList = (List<T>)this.Items;
Type propertyType = property.PropertyType;
PropertyComparer<T> comparer;
if (!this.comparers.TryGetValue(propertyType, out comparer))
{
comparer = new PropertyComparer<T>(property, direction);
this.comparers.Add(propertyType, comparer);
}
comparer.SetPropertyAndDirection(property, direction);
itemsList.Sort(comparer);
this.propertyDescriptor = property;
this.listSortDirection = direction;
this.isSorted = true;
this.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
}
protected override void RemoveSortCore()
{
this.isSorted = false;
this.propertyDescriptor = base.SortPropertyCore;
this.listSortDirection = base.SortDirectionCore;
this.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
}
protected override int FindCore(PropertyDescriptor property, object key)
{
int count = this.Count;
for (int i = 0; i < count; ++i)
{
T element = this[i];
if (property.GetValue(element).Equals(key))
{
return i;
}
}
return -1;
}
}
如果你愿意使用反射,你可以做如下的事情。
注意:我假设您使用的是DataGridView.ColumnHeaderMouseClick Event
,但这不会改变这种方法的核心。 关键是您需要动态标识表示要OrderBy
的列名称的字符串值。 如果您确实需要/想要,可以对此关联进行硬编码。
private void dataGridView2_ColumnHeaderMouseClick(
object sender, DataGridViewCellMouseEventArgs e)
{
...
var sortCol = dataGridView2.Columns[e.ColumnIndex];
var colName = sortCol.Name;
dataGridView2.DataSource = listPlayers.Select(s => new { voornaam = s.Voornaam, Achternaam = s.Achternaam, positie = s.Positie, Nationaltieit = s.Nationaliteit, Leeftijd = s.Age, Aanval = s.Aanval, Verdediging = s.Verdediging, Gemiddeld = s.Gemiddeld, waarde = s.TransferWaarde })
.OrderBy(s => typeof(SpelerData).GetProperty(colName))
.ToList();
...
}