如何在用户单击列标题时启用DataGridViewsorting?

我有一个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作为默认sorting,但是我还想让用户在点击列标题时进行sorting。

这种方式不会以任何方式修改数据,这只是一个客户端的好处,允许在用他们的眼睛扫描屏幕时更容易地search信息。

感谢您的build议。

将所有列(可由用户sorting)将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查询,它不会被sorting。 所以请通过这个链接来解释如何创build一个可sorting的绑定列表,然后将其作为数据源提供给datagridview。

正如Nirajbuild议的那样,使用SortableBindingList 。 我已经用DataGridView成功地使用了它。

这是我使用的更新代码的链接 – 呈现SortableBindingList – Take Two

只要将这两个源文件添加到您的项目中,就可以开始工作了。

源位于SortableBindingList.zip中

您的数据网格需要首先绑定到可sorting列表。

创build此事件处理程序:

  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; } 

并像这样初始化每个datragrid的事件:

  dataGridView1.DataBindingComplete += MakeColumnsSortable_DataBindingComplete; 

你可以像这样使用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() } } 

亲爱的:保持简单,愚蠢

方式A:在使用DataBindingsorting时实现自己的SortableBindingList类。

方式B:使用列表<string>sorting也可以,但不适用于DataBinding

如果您收到类似的错误消息

在System.Windows.Forms.dll中发生未处理的types为“System.NullReferenceException”的exception

如果你使用SortableBindingList,你的代码可能会在DataGridView行上使用一些循环,并尝试访问空的最后一行! (BindingSource = null)

如果你不需要允许用户直接在DataGridView中添加新行,这行代码很容易解决这个问题:

 InitializeComponent(); m_dataGridView.AllowUserToAddRows = false; // after components initialized ... 
  1. 创build一个包含所有你需要的属性的类,然后在构造函数中填充它们

     class Student { int _StudentId; public int StudentId {get;} string _Name; public string Name {get;} ... public Student(int studentId, string name ...) { _StudentId = studentId; _Name = name; ... } } 
  2. 创build一个IComparer <Student>类,以便能够sorting

     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; } } 
  3. 在包含datagrid添加的表单中

     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]; } 
  4. 在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(); } 

希望这可以帮助

还有一种方法是使用“System.Linq.Dynamic”库。 你可以从Nuget获得这个库。 不需要任何自定义实现:)。

 using System.Linq.Dynamic; private bool sortAscending = false; private void dataGridView_ColumnHeaderMouseClick ( object sender, DataGridViewCellMouseEventArgs e ) { if ( sortAscending ) dataGridView.DataSource = list.OrderBy ( dataGridView.Columns [ e.ColumnIndex ].DataPropertyName ).ToList ( ); else dataGridView.DataSource = list.OrderBy ( dataGridView.Columns [ e.ColumnIndex ].DataPropertyName ).Reverse ( ).ToList ( ); sortAscending = !sortAscending; } 

以防有人仍然在寻找它,我做了VS 2008 C#。

在事件ColumnHeaderMouseClick上,为gridview添加一个数据绑定,并按字段发送按照参数的顺序。 你可以得到点击字段如下:

 dgView.Columns[e.ColumnIndex].Name 

在我的情况下,标题的名称与查看字段名称相似。

我有一个BindingList <>对象作为数据源绑定到dataGridView。

 BindingList x1; x1 = new BindingList<sourceObject>(); BindingSource bsx1 = new BindingSource(); bsx1.DataSource = x1; dataGridView1.DataSource = bsx1; 

当我点击列标题时,不会进行sorting。 我使用了由Tom Bushell提供的SortableBindingList答案。 在我的项目中包含了两个源文件

  1. SortableBindingList.cs
  2. PropertyComparer.cs

然后这个改变是对我的代码:

 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; 

在这些改变之后,我对程序进行了构build。 我现在可以通过单击列标题进行sorting。 只有两行需要更改,它们在上面的代码片段中用尾随注释突出显示。

当使用entity framework(在这种情况下是版本6)时,相当简单的解决scheme。 我不确定,但似乎ObservableCollectionExtensions.ToBindingList<T>方法返回可sorting绑定列表的实现。 我还没有find源代码来确认这个假设,但从这个方法返回的对象与DataGridView得很好,尤其是当通过点击其标题sorting列时。

代码非常简单,只依赖于.net和entity framework类:

 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; 

我build议使用一个DataTable.DefaultView作为一个数据源。 然后在下面的行。

 foreach (DataGridViewColumn column in gridview.Columns) { column.SortMode = DataGridViewColumnSortMode.Automatic; } 

之后,gridview本身将pipe理sorting(支持升序或降序)。

您不需要创build绑定数据源。 如果您想对所有列应用sorting,这是我的更通用的解决scheme;

 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(); } 

确保你订阅你的数据网格到事件ColumnHeaderMouseClick 。 当用户点击列时,它将按降序sorting。 如果再次单击相同的列标题,sorting将按升序应用。