我的表单上有一个datagridview,我填充它:
dataGridView1.DataSource = students.Select(s => new { ID = s.StudentId, RUDE = s.RUDE, Nombre = s.Name, Apellidos = s.LastNameFather + " " + s.LastNameMother, Nacido = s.DateOfBirth })
.OrderBy(s => s.Apellidos)
.ToList();
现在,我使用s.Apellidos作为默认排序,但我也希望允许用户在单击列标题时进行排序。
这种不以任何方式修改数据,只是客户端奖励,以便在用眼睛扫描屏幕时更容易搜索信息。
感谢您的建议。
答案 0 :(得分:48)
将所有列(可由用户排序)SortMode属性设置为Automatic
dataGridView1.DataSource = students.Select(s => new { ID = s.StudentId, RUDE = s.RUDE, Nombre = s.Name, Apellidos = s.LastNameFather + " " + s.LastNameMother, Nacido = s.DateOfBirth })
.OrderBy(s => s.Apellidos)
.ToList();
foreach(DataGridViewColumn column in dataGridView1.Columns)
{
column.SortMode = DataGridViewColumnSortMode.Automatic;
}
编辑:由于您的datagridview与linq查询绑定,因此不会对其进行排序。所以请通过这个link来解释如何创建一个可排序的绑定列表,然后将其作为数据源提供给datagridview。
答案 1 :(得分:26)
正如Niraj建议的那样,使用 SortableBindingList 。我已经非常成功地使用了DataGridView。
以下是我使用的更新代码的链接 - Presenting the SortableBindingList - Take Two
只需将两个源文件添加到您的项目中,您就可以开展业务了。
答案 2 :(得分:7)
您的数据网格首先需要绑定到可排序列表。
创建此事件处理程序:
void MakeColumnsSortable_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
//Add this as an event on DataBindingComplete
DataGridView dataGridView = sender as DataGridView;
if (dataGridView == null)
{
var ex = new InvalidOperationException("This event is for a DataGridView type senders only.");
ex.Data.Add("Sender type", sender.GetType().Name);
throw ex;
}
foreach (DataGridViewColumn column in dataGridView.Columns)
column.SortMode = DataGridViewColumnSortMode.Automatic;
}
并初始化每个datragrids的事件,如下所示:
dataGridView1.DataBindingComplete += MakeColumnsSortable_DataBindingComplete;
答案 3 :(得分:5)
您可以像这样使用DataGridViewColoumnHeaderMouseClick事件:
Private string order = String.Empty;
private void dgvDepartment_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
if (order == "d")
{
order = "a";
dataGridView1.DataSource = students.Select(s => new { ID = s.StudentId, RUDE = s.RUDE, Nombre = s.Name, Apellidos = s.LastNameFather + " " + s.LastNameMother, Nacido = s.DateOfBirth }) .OrderBy(s => s.Apellidos).ToList();
}
else
{
order = "d";
dataGridView1.DataSource = students.Select(s => new { ID = s.StudentId, RUDE = s.RUDE, Nombre = s.Name, Apellidos = s.LastNameFather + " " + s.LastNameMother, Nacido = s.DateOfBirth }.OrderByDescending(s => s.Apellidos) .ToList()
}
}
答案 4 :(得分:5)
您无需创建绑定数据源。如果您想对所有列应用排序,这是我的更通用的解决方案;
enableMouseTracking
确保您将数据网格订阅到活动private int _previousIndex;
private bool _sortDirection;
private void gridView_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.ColumnIndex == _previousIndex)
_sortDirection ^= true; // toggle direction
gridView.DataSource = SortData(
(List<MainGridViewModel>)gridReview.DataSource, gridReview.Columns[e.ColumnIndex].Name, _sortDirection);
_previousIndex = e.ColumnIndex;
}
public List<MainGridViewModel> SortData(List<MainGridViewModel> list, string column, bool ascending)
{
return ascending ?
list.OrderBy(_ => _.GetType().GetProperty(column).GetValue(_)).ToList() :
list.OrderByDescending(_ => _.GetType().GetProperty(column).GetValue(_)).ToList();
}
。当用户点击列时,它将按降序排序。如果再次单击相同的列标题,则将按升序应用排序。
答案 5 :(得分:3)
在使用Entity Framework(在这种情况下为版本6)时,有一个非常简单的解决方案。我不确定,但似乎ObservableCollectionExtensions.ToBindingList<T>
方法返回可排序绑定列表的实现。我没有找到确认此假设的源代码,但是从此方法返回的对象非常适用于DataGridView
,尤其是在通过单击其标题对列进行排序时。
代码非常简单,只依赖于.net和实体框架类:
using System.Data.Entity;
IEnumerable<Item> items = MethodCreatingItems();
var observableItems = new System.Collections.ObjectModel.ObservableCollection<Item>(items);
System.ComponentModel.BindingList<Item> source = observableItems.ToBindingList();
MyDataGridView.DataSource = source;
答案 6 :(得分:3)
另一种方法是使用“System.Linq.Dynamic”库。您可以从Nuget获取此库。无需任何自定义实现或可排序列表:)
import pandas as pd
import numpy as np
results = pd.DataFrame({'scores':[78.5, 91.0, 103.5], 'outcomes':[1,0,1]})
thresholds = [4.7562029077978352, 4.6952820449271861, 4.6343611820565371, 4.5734403191858881, 103.5, 98.5, 93.5, 88.5, 83.5, 78.5]
thresholds_col = ['{:.16f}'.format(e) for e in thresholds]
data = results.outcomes[:,np.newaxis] * ((results.scores[:,np.newaxis] - thresholds > 0))
results = results.join(pd.DataFrame(data=data, columns=thresholds_col))
print results
print results[thresholds_col]
Out[79]:
4.7562029077978352 4.6952820449271861 4.6343611820565371 \
0 1 1 1
1 0 0 0
2 1 1 1
4.5734403191858881 103.5000000000000000 98.5000000000000000 \
0 1 0 0
1 0 0 0
2 1 0 1
93.5000000000000000 88.5000000000000000 83.5000000000000000 \
0 0 0 0
1 0 0 0
2 1 1 1
78.5000000000000000
0 0
1 0
2 1
答案 7 :(得分:2)
KISS:保持简单,愚蠢
方式A: 喜欢使用 DataBinding 和排序时实现自己的SortableBindingList类。
方式B: 使用列表&lt;字符串&gt; 排序也可以,但不适用于 DataBinding 。
答案 8 :(得分:1)
创建一个包含所需属性的类,并在构造函数中填充它们
class Student
{
int _StudentId;
public int StudentId {get;}
string _Name;
public string Name {get;}
...
public Student(int studentId, string name ...)
{ _StudentId = studentId; _Name = name; ... }
}
创建IComparer&lt;学生&gt; class,能够排序
class StudentSorter : IComparer<Student>
{
public enum SField {StudentId, Name ... }
SField _sField; SortOrder _sortOrder;
public StudentSorder(SField field, SortOrder order)
{ _sField = field; _sortOrder = order;}
public int Compare(Student x, Student y)
{
if (_SortOrder == SortOrder.Descending)
{
Student tmp = x;
x = y;
y = tmp;
}
if (x == null || y == null)
return 0;
int result = 0;
switch (_sField)
{
case SField.StudentId:
result = x.StudentId.CompareTo(y.StudentId);
break;
case SField.Name:
result = x.Name.CompareTo(y.Name);
break;
...
}
return result;
}
}
在包含datagrid add
的表单中ListDictionary sortOrderLD = new ListDictionary(); //if less than 10 columns
private SortOrder SetOrderDirection(string column)
{
if (sortOrderLD.Contains(column))
{
sortOrderLD[column] = (SortOrder)sortOrderLD[column] == SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending;
}
else
{
sortOrderLD.Add(column, SortOrder.Ascending);
}
return (SortOrder)sortOrderLD[column];
}
在datagridview_ColumnHeaderMouseClick事件处理程序中执行类似这样的操作
private void dgv_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
StudentSorter sorter = null;
string column = dGV.Columns[e.ColumnIndex].DataPropertyName; //Use column name if you set it
if (column == "StudentId")
{
sorter = new StudentSorter(StudentSorter.SField.StudentId, SetOrderDirection(column));
}
else if (column == "Name")
{
sorter = new StudentSorter(StudentSorter.SField.Name, SetOrderDirection(column));
}
...
List<Student> lstFD = datagridview.DataSource as List<Student>;
lstFD.Sort(sorter);
datagridview.DataSource = lstFD;
datagridview.Refresh();
}
希望这有帮助
答案 9 :(得分:1)
如果收到类似
的错误消息类型'System.NullReferenceException'的未处理异常 发生在System.Windows.Forms.dll
中
如果您使用SortableBindingList,您的代码可能会在DataGridView行上使用一些循环,并尝试访问空的最后一行! (BindingSource = null)
如果您不需要允许用户直接在DataGridView中添加新行,这行代码可以轻松解决问题:
InitializeComponent();
m_dataGridView.AllowUserToAddRows = false; // after components initialized
...
答案 10 :(得分:0)
万一有人还在寻找它,我是在VS 2008 C#上做到的。
在Event ColumnHeaderMouseClick上,为gridview添加数据绑定,并像参数一样按字段发送订单。您可以按如下方式获取单击的字段:
dgView.Columns[e.ColumnIndex].Name
在我的例子中,标题的名称与视图字段名称类似。
答案 11 :(得分:0)
我有一个BindingList&lt;&gt; object绑定为dataGridView的数据源。
BindingList x1;
x1 = new BindingList<sourceObject>();
BindingSource bsx1 = new BindingSource();
bsx1.DataSource = x1;
dataGridView1.DataSource = bsx1;
单击列标题时,不会进行排序。 我使用了Tom Bushell提供的SortableBindingList答案。 已将两个源文件包含到我的项目中
然后对我的代码进行了更改:
Be.Timvw.Framework.ComponentModel.SortableBindingList x1; // 1
x1 = new Be.Timvw.Framework.ComponentModel.SortableBindingList<sourceObject>(); // 2
BindingSource bsx1 = new BindingSource();
bsx1.DataSource = x1;
dataGridView1.DataSource = bsx1;
在这些更改后,我对我的程序进行了构建。我现在可以通过单击列标题进行排序。只需要更改两行,它们在上面的代码片段中通过尾随注释突出显示。
答案 12 :(得分:0)
我建议使用DataTable.DefaultView作为DataSource。然后是下面的一行。
foreach (DataGridViewColumn column in gridview.Columns)
{
column.SortMode = DataGridViewColumnSortMode.Automatic;
}
之后gridview本身将管理排序(支持Ascending或Descending。)
答案 13 :(得分:0)
将此行放在您的Windows窗体中(在加载时或更好地使用公共方法,例如&#34; binddata&#34;):
//
// bind the data and make the grid sortable
//
this.datagridview1.MakeSortable( myenumerablecollection );
将此代码放在名为DataGridViewExtensions.cs(或类似)
的文件中// MakeSortable extension.
// this will make any enumerable collection sortable on a datagrid view.
//
// BEGIN MAKESORTABLE - Mark A. Lloyd
//
// Enables sort on all cols of a DatagridView
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
public static class DataGridViewExtensions
{
public static void MakeSortable<T>(
this DataGridView dataGridView,
IEnumerable<T> dataSource,
SortOrder defaultSort = SortOrder.Ascending,
SortOrder initialSort = SortOrder.None)
{
var sortProviderDictionary = new Dictionary<int, Func<SortOrder, IEnumerable<T>>>();
var previousSortOrderDictionary = new Dictionary<int, SortOrder>();
var itemType = typeof(T);
dataGridView.DataSource = dataSource;
foreach (DataGridViewColumn c in dataGridView.Columns)
{
object Provider(T info) => itemType.GetProperty(c.Name)?.GetValue(info);
sortProviderDictionary[c.Index] = so => so != defaultSort ?
dataSource.OrderByDescending<T, object>(Provider) :
dataSource.OrderBy<T,object>(Provider);
previousSortOrderDictionary[c.Index] = initialSort;
}
async Task DoSort(int index)
{
switch (previousSortOrderDictionary[index])
{
case SortOrder.Ascending:
previousSortOrderDictionary[index] = SortOrder.Descending;
break;
case SortOrder.None:
case SortOrder.Descending:
previousSortOrderDictionary[index] = SortOrder.Ascending;
break;
default:
throw new ArgumentOutOfRangeException();
}
IEnumerable<T> sorted = null;
dataGridView.Cursor = Cursors.WaitCursor;
dataGridView.Enabled = false;
await Task.Run(() => sorted = sortProviderDictionary[index](previousSortOrderDictionary[index]).ToList());
dataGridView.DataSource = sorted;
dataGridView.Enabled = true;
dataGridView.Cursor = Cursors.Default;
}
dataGridView.ColumnHeaderMouseClick+= (object sender, DataGridViewCellMouseEventArgs e) => DoSort(index: e.ColumnIndex);
}
}
答案 14 :(得分:0)
在我的情况下,问题是我将DataSource
设置为object
,这就是为什么它没有被排序的原因。从object
更改为DataTable
后,它可以很好地工作,无需任何代码补充。