在多列上对DataGridView进行排序?

Bla*_*ght 8 c# sorting datagridview

我已经搜索了一个在多列上对DataGridView进行排序的示例,但似乎无法找到符合我想要的示例.

基本上,我有一个绑定的DataGridView控件(绑定到DataTable/DataView),绑定的DataTable有两列: - priority和date.我想按优先顺序按日期排序.也就是说,优先级列采用优先级,然后是日期,但两者都可以是升序或降序.

因此,例如,我可能具有低优先级,早期日期优先(按优先级asc,日期asc排序),并且通过单击日期列标题,切换到低优先级,晚期日期优先(按优先级顺序asc,日期desc).如果我然后单击优先级,我希望首先具有高优先级,然后是较晚的日期(日期列的当前排序顺序 - 按优先级desc排序,日期desc),但是然后可以单击日期列标题切换到高优先级,早期日期(按优先级desc,日期asc排序).

理想情况下,我想在两列上对字形进行排序以显示升序或降序.

我们将非常感激地提出任何想法或建议.

这个(见下文)似乎非常接近,但字形无法正常工作.

using System;
using System.Windows.Forms;

namespace WindowsFormsApplication4
{
  public partial class Form1 : Form
  {
     DataSet1 dataset;

     public Form1()
     {
        InitializeComponent();

        dataset = new DataSet1(); // two columns: Priority(Int32) and date (DateTime)
        dataset.DataTable1.AddDataTable1Row(1, DateTime.Parse("01-jan-10"));
        dataset.DataTable1.AddDataTable1Row(1, DateTime.Parse("02-jan-10"));
        dataset.DataTable1.AddDataTable1Row(1, DateTime.Parse("03-jan-10"));
        dataset.DataTable1.AddDataTable1Row(2, DateTime.Parse("04-jan-10"));
        dataset.DataTable1.AddDataTable1Row(2, DateTime.Parse("05-jan-10"));
        dataset.DataTable1.AddDataTable1Row(2, DateTime.Parse("06-jan-10"));
        dataset.DataTable1.AddDataTable1Row(3, DateTime.Parse("07-jan-10"));
        dataset.DataTable1.AddDataTable1Row(3, DateTime.Parse("08-jan-10"));
        dataset.DataTable1.AddDataTable1Row(3, DateTime.Parse("09-jan-10"));

        dataGridView1.DataSource = dataset.DataTable1.DefaultView;

        dataGridView1.AllowUserToAddRows = false;

        dataGridView1.Columns[0].SortMode = DataGridViewColumnSortMode.Programmatic;
        dataGridView1.Columns[1].SortMode = DataGridViewColumnSortMode.Programmatic;

        dataGridView1.Columns[0].HeaderCell.SortGlyphDirection = SortOrder.Ascending;
        dataGridView1.Columns[1].HeaderCell.SortGlyphDirection = SortOrder.Ascending;
     }

     private void dataGridView1_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
     {
        DataGridViewColumn[] column = new[] { dataGridView1.Columns[0], dataGridView1.Columns[1] };

        DataGridViewColumnHeaderCell headerCell = dataGridView1.Columns[e.ColumnIndex].HeaderCell;

        if (headerCell.SortGlyphDirection != SortOrder.Ascending)
           headerCell.SortGlyphDirection = SortOrder.Ascending;
        else
           headerCell.SortGlyphDirection = SortOrder.Descending;

        String sort = column[0].DataPropertyName + " " + fnSortDirection(column[0])
                    + ", "
                    + column[1].DataPropertyName + " " + fnSortDirection(column[1]);
        dataset.DataTable1.DefaultView.Sort = sort;
        this.textBox1.Text = sort;
     }

     private String fnSortDirection(DataGridViewColumn column)
     {
        return column.HeaderCell.SortGlyphDirection != SortOrder.Descending ? "asc" : "desc";
     }
  }
}
Run Code Online (Sandbox Code Playgroud)

Cod*_*ray 7

我第一次看到这个,我完全错过了同时按列排序的部分(我的错,不是你的;问题非常清楚).

如果是这种情况,您将不得不编写自己处理此问题的代码.DataGridView默认情况下,提供的控件不支持多列排序.幸运的是,其他人已经为你实现了很多工作.以下是一些示例:

或者,如果将DataGridView数据源绑定到数据源,则可以在多个列上对该数据源进行排序,并且DataGridView控件将遵循该排序.实现IBindingListView和公开Sort属性的任何数据源都可用于多列排序.


但是,无论您选择启用多列排序的路径如何,您都不会在强制DataGridView显示多列上的排序箭头字形方面取得多大成功.这里最简单的解决方案是自定义绘制列标题以提供您自己的排序标志符号.

为此,请将DataGridView.CellPainting事件处理程序附加到事件并检查RowIndex-1(表示列标题).有业主绘制列标题的全样本这里.我强烈建议坚持使用传统的箭头图标,但一旦你走这条路线,选项真的是无限的.您可以使列标题看起来像您想要的任何内容,甚至可以使用不同的图标指示排序顺序中每列的相对权重.

您还可以选择从中派生新类DataGridViewColumnHeaderCell并覆盖其Paint方法.这可能是一种更清洁,更面向对象的方式来完成同样的事情.


Bla*_*ght 4

好的。

根据科迪上面的建议,我现在得到了一些似乎按预期工作的东西。我已经对 HeaderCell 进行了子类化并覆盖了 Paint 方法(但通过在紧邻 base.Paint 之前设置 SortGlyphDirection 进行了欺骗),并且 DGV 现在绘制了多个排序字形。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace WindowsFormsApplication4
{
  public partial class Form1 : Form
  {
     DataSet1 dataset;

     public Form1()
     {
        InitializeComponent();

        dataset = new DataSet1(); // three columns: Priority(Int32), Date (DateTime) and Description(String)
        dataset.DataTable1.AddDataTable1Row(1, DateTime.Parse("01-jan-10"), "this");
        dataset.DataTable1.AddDataTable1Row(1, DateTime.Parse("02-jan-10"), "is");
        dataset.DataTable1.AddDataTable1Row(1, DateTime.Parse("03-jan-10"), "a");
        dataset.DataTable1.AddDataTable1Row(2, DateTime.Parse("04-jan-10"), "sample");
        dataset.DataTable1.AddDataTable1Row(2, DateTime.Parse("05-jan-10"), "of");
        dataset.DataTable1.AddDataTable1Row(2, DateTime.Parse("06-jan-10"), "the");
        dataset.DataTable1.AddDataTable1Row(3, DateTime.Parse("07-jan-10"), "data");
        dataset.DataTable1.AddDataTable1Row(3, DateTime.Parse("08-jan-10"), "in");
        dataset.DataTable1.AddDataTable1Row(3, DateTime.Parse("09-jan-10"), "use");

        dataGridView1.DataSource = dataset.DataTable1.DefaultView;

        dataGridView1.AllowUserToAddRows = false;

        dataGridView1.Columns[0].HeaderCell = new MyDataGridViewColumnHeaderCell();
        dataGridView1.Columns[1].HeaderCell = new MyDataGridViewColumnHeaderCell();

        dataGridView1.Columns[0].SortMode = DataGridViewColumnSortMode.Programmatic;
        dataGridView1.Columns[1].SortMode = DataGridViewColumnSortMode.Programmatic;
     }

     private void dataGridView1_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
     {
        DataGridViewColumn clickedColumn = dataGridView1.Columns[e.ColumnIndex];

        if (clickedColumn.HeaderCell is MyDataGridViewColumnHeaderCell)
        {
           DoMultiColumnSort();
        }
        else
        {
           dataGridView1.Columns.OfType<DataGridViewColumn>()
                                .Where(column => column.HeaderCell is MyDataGridViewColumnHeaderCell)
                                .ForEach(column => ((MyDataGridViewColumnHeaderCell)column.HeaderCell).SortOrderDirection = SortOrder.None);
        }

        this.textBox1.Text = dataset.DataTable1.DefaultView.Sort;
     }

     private void DoMultiColumnSort()
     {
        var sortClauses = dataGridView1.Columns.OfType<DataGridViewColumn>()
                                               .Where(column => column.HeaderCell is MyDataGridViewColumnHeaderCell)
                                               .Select(column => GetSortClause(column));

        dataset.DataTable1.DefaultView.Sort = String.Join(",", sortClauses);
     }

     private String GetSortClause(DataGridViewColumn column)
     {
        SortOrder direction = column.HeaderCell.SortGlyphDirection;

        if (column.HeaderCell is MyDataGridViewColumnHeaderCell)
        {
           direction = ((MyDataGridViewColumnHeaderCell)column.HeaderCell).SortOrderDirection;
        }

        return column.DataPropertyName + " " + (direction == SortOrder.Descending ? "DESC" : "ASC");
     }
  }

  public partial class MyDataGridViewColumnHeaderCell : DataGridViewColumnHeaderCell
  {
     public SortOrder SortOrderDirection { get; set; } // defaults to zero = SortOrder.None;

     protected override void Paint(System.Drawing.Graphics graphics, System.Drawing.Rectangle clipBounds, System.Drawing.Rectangle cellBounds, int rowIndex, DataGridViewElementStates dataGridViewElementState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
     {
        this.SortGlyphDirection = this.SortOrderDirection;
        base.Paint(graphics, clipBounds, cellBounds, rowIndex, dataGridViewElementState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);
     }

     public override object Clone()
     {
        MyDataGridViewColumnHeaderCell result = (MyDataGridViewColumnHeaderCell)base.Clone();
        result.SortOrderDirection = this.SortOrderDirection;
        return result;
     }

     protected override void OnClick(DataGridViewCellEventArgs e)
     {
        this.SortOrderDirection = (this.SortOrderDirection != SortOrder.Ascending) ? SortOrder.Ascending : SortOrder.Descending;
        base.OnClick(e);
     }
  }

  public static partial class Extensions
  {
     public static void ForEach<T>(this IEnumerable<T> value, Action<T> action) { foreach (T item in value) { action(item); } }
  }
}
Run Code Online (Sandbox Code Playgroud)