C#DataGridView使用Generic List作为基础源进行排序

我正在使用Windows窗体DataGridView来显示MyObject对象的通用列表。

首先,我将此集合包装到BindingSource集合中,然后:

 dataGridView.DataSource = myBindingSource; 

我想要做的是允许用户通过单击表示MyObject中具体属性的列的标题对列进行排序。

我读过一些文章,我应该在绑定之前进行排序。 但是,如果我想实时对列进行排序,那么它就无法帮助我。

问题是,我到底需要做什么,所以我可以看到 DataGridView中的排序箭头我可以对每一列进行排序

完整代码,用于对datagridview列进行排序,其数据源是通用List

 //----------------------------------------------------------------------------------------- //In the form - In constructor or form load, populate the grid. //-------------------------------------------------------------------------------------------- List students; private void PopulateList() { student std1 = new student("sss", 15, "Female"); student std2 = new student("ddd", 12, "Male"); student std3 = new student("zzz", 16, "Male"); student std4 = new student("qqq", 14, "Female"); student std5 = new student("aaa", 11, "Male"); student std6 = new student("lll", 13, "Female"); students = new List(); students.Add(std1); students.Add(std2); students.Add(std3); students.Add(std4); students.Add(std5); students.Add(std6); dataGridView1.DataSource = students; } //--------------------------------------------------------------------------------------------- //Comparer class to perform sorting based on column name and sort order //--------------------------------------------------------------------------------------------- class StudentComparer : IComparer { string memberName = string.Empty; // specifies the member name to be sorted SortOrder sortOrder = SortOrder.None; // Specifies the SortOrder. ///  /// constructor to set the sort column and sort order. ///  ///  ///  public StudentComparer(string strMemberName, SortOrder sortingOrder) { memberName = strMemberName; sortOrder = sortingOrder; } ///  /// Compares two Students based on member name and sort order /// and return the result. ///  ///  ///  ///  public int Compare(Student Student1, Student Student2) { int returnValue = 1; switch (memberName) { case "Name" : if (sortOrder == SortOrder.Ascending) { returnValue = Student1.Name.CompareTo(Student2.Name); } else { returnValue = Student2.Name.CompareTo(Student1.Name); } break; case "Sex": if (sortOrder == SortOrder.Ascending) { returnValue = Student1.Sex.CompareTo(Student2.Sex); } else { returnValue = Student2.Sex.CompareTo(Student1.Sex); } break; default: if (sortOrder == SortOrder.Ascending) { returnValue = Student1.Name.CompareTo(Student2.Name); } else { returnValue = Student2.Name.CompareTo(Student1.StudentId); } break; } return returnValue; } } //--------------------------------------------------------------------------------------------- // Performing sort on click on Column Header //--------------------------------------------------------------------------------------------- private void dataGridView1_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e) { //get the current column details string strColumnName = dataGridView1.Columns[e.ColumnIndex].Name; SortOrder strSortOrder = getSortOrder(e.ColumnIndex); students.Sort(new StudentComparer(strColumnName, strSortOrder)); dataGridView1.DataSource = null; dataGridView1.DataSource = students; customizeDataGridView(); dataGridView1.Columns[e.ColumnIndex].HeaderCell.SortGlyphDirection = strSortOrder; } ///  /// Get the current sort order of the column and return it /// set the new SortOrder to the columns. ///  ///  /// SortOrder of the current column private SortOrder getSortOrder(int columnIndex) { if (dataGridView1.Columns[columnIndex].HeaderCell.SortGlyphDirection == SortOrder.None || dataGridView1.Columns[columnIndex].HeaderCell.SortGlyphDirection == SortOrder.Descending) { dataGridView1.Columns[columnIndex].HeaderCell.SortGlyphDirection = SortOrder.Ascending; return SortOrder.Ascending; } else { dataGridView1.Columns[columnIndex].HeaderCell.SortGlyphDirection = SortOrder.Descending; return SortOrder.Descending; } } 

我发现很难相信网格不提供开箱即用的基本排序,不需要代码。 毕竟,必须处理标题点击事件并调用DataGridView.Sort指示列(由点击的内容,由网格跟踪确定)和排序方向(由当前排序状态确定,由网格跟踪)是非常愚蠢的)。

为什么没有简单的SortMode或AllowUserToSort属性默认执行完全相同的操作?

我已将网格绑定到List,并且我将列映射到的属性都是基本类型,如string,int,DateTime等。 所有这些都是IC Comparable。 那么为什么我还需要写一行代码呢? 特别是考虑到文档的内容如下:

默认情况下,用户可以通过单击文本框列的标题对DataGridView控件中的数据进行排序。

MSDN

这是Framework 3.0文档,我的目标是3.5,但“其他版本”都是指Visual Studio的版本,而不是Framework的版本。 微软究竟发生了什么?!?

本文“呈现SortableBindingList”中的一个很好的解决方案: http ://www.timvw.be/2007/02/22/presenting-the-sortablebindinglistt/

我的解决方案是:

我自己使用myBindingSource,我进行排序,分组..无论是在一个单独的线程中。 然后我只是将结果绑定到DataGridView

 myDataGridView.DataSource = bindingSource; 

为此我设置了所有列'Programatically' (在设计器中)然后我通过设置手动添加箭头(ASCENDING / DESCENDING)

 cell.SortGlyphDirection = ... ; 

在代码背后。

这是一个使用Reflection和Linq按列排序的更简单的解决方案。 dataGridView1的DataSource设置为compareList,声明为:

  private List compareList; private void dataGridView1_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e) { string strColumnName = dataGridView1.Columns[e.ColumnIndex].Name; SortOrder strSortOrder = getSortOrder(e.ColumnIndex); if (strSortOrder == SortOrder.Ascending) { compareList = compareList.OrderBy(x => typeof(CompareInfo).GetProperty(strColumnName).GetValue(x, null)).ToList(); } else { compareList = compareList.OrderByDescending(x => typeof(CompareInfo).GetProperty(strColumnName).GetValue(x, null)).ToList(); } dataGridView1.DataSource = compareList; dataGridView1.Columns[e.ColumnIndex].HeaderCell.SortGlyphDirection = strSortOrder; } private SortOrder getSortOrder(int columnIndex) { if (dataGridView1.Columns[columnIndex].HeaderCell.SortGlyphDirection == SortOrder.None || dataGridView1.Columns[columnIndex].HeaderCell.SortGlyphDirection == SortOrder.Descending) { dataGridView1.Columns[columnIndex].HeaderCell.SortGlyphDirection = SortOrder.Ascending; return SortOrder.Ascending; } else { dataGridView1.Columns[columnIndex].HeaderCell.SortGlyphDirection = SortOrder.Descending; return SortOrder.Descending; } } public class CompareInfo { public string FileName { get; set; } public string UAT_Folder { get; set; } public string UAT_Path { get { return UAT_Folder + FileName; } } public string PROD_Folder { get; set; } public string PROD_Path { get { return PROD_Folder + FileName; } } } 

您可能还想看看这篇文章,您可以获得两个有趣的链接来实现自定义的SortableBindingList:

当数据源绑定到List(Of T)时对Datagridview列进行排序

看到这个艺术

http://msdn.microsoft.com/en-us/library/0868ft3z.aspx

通过阅读它我看到这个“此方法通过比较指定列中的值来排序DataGridView的内容。默认情况下,排序操作将使用Compare方法使用DataGridViewCell .. ::来比较列中的单元格对。价值财产。“

最诚挚的问候,iordan

在绑定到List时,使用DataGridView解决排序问题的另一个选择是,如果您不处理大型数据集,那么您可能尝试将List转换为DataTable,然后将生成的DataTable绑定到BindingSource / DataGridView。

这需要IComparer的自定义实现。 在我的情况下,我正在处理一个较小的列表,但还有更多的字段要显示。 因此,实施IComparer意味着编写太多锅炉板代码。

检查这个将List转换为DataTable的简洁方法: https : //stackoverflow.com/a/34062898/4534493

如果最好创建自己的用户控件,可以使用以下代码创建自定义排序方法:

  private string _lastSortColumn; private ListSortDirection _lastSortDirection; public void Sort(DataGridViewColumn column) { // Flip sort direction, if the column chosen was the same as last time if (column.Name == _lastSortColumn) _lastSortDirection = 1 - _lastSortDirection; // Otherwise, reset the sort direction to its default, ascending else { _lastSortColumn = column.Name; _lastSortDirection = ListSortDirection.Ascending; } // Prep data for sorting var data = (IEnumerable)DataSource; var orderProperty = column.DataPropertyName; // Sort data if (_lastSortDirection == ListSortDirection.Ascending) DataSource = data.OrderBy(x => x.GetType().GetProperty(orderProperty).GetValue(x, null)).ToList(); else DataSource = data.OrderByDescending(x => x.GetType().GetProperty(orderProperty).GetValue(x, null)).ToList(); // Set direction of the glyph Columns[column.Index].HeaderCell.SortGlyphDirection = _lastSortDirection == ListSortDirection.Ascending ? SortOrder.Ascending : SortOrder.Descending; } 

然后,您可以覆盖标题单击方法以调用排序函数:

  protected override void OnColumnHeaderMouseClick(DataGridViewCellMouseEventArgs e) { base.OnColumnHeaderMouseClick(e); var column = Columns[e.ColumnIndex]; if (column.SortMode == DataGridViewColumnSortMode.Automatic || column.SortMode == DataGridViewColumnSortMode.NotSortable) Sort(column); }