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

时间:2009-09-04 06:34:10

标签: c# sorting datagridview

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

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

dataGridView.DataSource = myBindingSource;

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

我读过一些文章,我应该在绑定之前进行排序。但是,如果我想实时对列进行排序,并且在已经绑定的情况下进行排序,它对我没有帮助。

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

10 个答案:

答案 0 :(得分:30)

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

//-----------------------------------------------------------------------------------------
//In the form - In constructor or form load, populate the grid.
//--------------------------------------------------------------------------------------------

    List<student> 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<student>();
        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<Student>
{
    string memberName = string.Empty; // specifies the member name to be sorted
    SortOrder sortOrder = SortOrder.None; // Specifies the SortOrder.

    /// <summary>
    /// constructor to set the sort column and sort order.
    /// </summary>
    /// <param name="strMemberName"></param>
    /// <param name="sortingOrder"></param>
    public StudentComparer(string strMemberName, SortOrder sortingOrder)
    {
        memberName = strMemberName;
        sortOrder = sortingOrder;
    }

    /// <summary>
    /// Compares two Students based on member name and sort order
    /// and return the result.
    /// </summary>
    /// <param name="Student1"></param>
    /// <param name="Student2"></param>
    /// <returns></returns>
    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;
    }

   /// <summary>
    /// Get the current sort order of the column and return it
    /// set the new SortOrder to the columns.
    /// </summary>
    /// <param name="columnIndex"></param>
    /// <returns>SortOrder of the current column</returns>
    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;
        }
    }

答案 1 :(得分:9)

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

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

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

  

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

MSDN

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

答案 2 :(得分:5)

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

答案 3 :(得分:2)

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

    private List<CompareInfo> 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; }
    }
}

答案 4 :(得分:1)

我的解决方案是:

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

myDataGridView.DataSource = bindingSource;

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

cell.SortGlyphDirection = ... ; 

代码背后。

答案 5 :(得分:0)

看这个artice

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

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

最诚挚的问候, 约尔丹

答案 6 :(得分:0)

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

Sort Datagridview columns when datasource binded to List(Of T)

答案 7 :(得分:0)

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

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

选中此项以便将List转换为DataTable的简洁方法:https://stackoverflow.com/a/34062898/4534493

答案 8 :(得分:0)

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

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

然后您可以覆盖标题click方法来调用您的排序函数:

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

答案 9 :(得分:0)

首先我使用了 System.Reflection; 然后:写这个方法

 public DataTable ToDataTable<T>(List<T> items)
    {
        DataTable dataTable = new DataTable(typeof(T).Name);
        //Get all the properties
        PropertyInfo[] Props = typeof(T).GetProperties(BindingFlags.Public | 
        BindingFlags.Instance);

        foreach (PropertyInfo prop in Props)
        {
            //Setting column names as Property names

            dataTable.Columns.Add(prop.Name);
        }
        foreach (T item in items)
        {
            var values = new object[Props.Length];

            for (int i = 0; i < Props.Length; i++)
            {
                //inserting property values to datatable rows

                values[i] = Props[i].GetValue(item, null);
            }
            dataTable.Rows.Add(values);
        }
           //put a breakpoint here and check datatable
        return dataTable;
    }

然后调用方法: DataTable dt = ToDataTable(lst.ToList());