在多列上对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"; } } } 

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

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

  • DataGridView多列排序 (CodeProject)
  • 如何允许在自定义数据绑定中按多列排序 (CodeProject)

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

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

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

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

DataGridView在所有情况下都绑定到DataSourceDataView,BindingSource,Table,DataSet +“tablename” )时,它引用DataView 。 获取对此DataView的引用并根据需要设置Sort (和Filter ):

 DataView dv = null; CurrencyManager cm = (CurrencyManager)(dgv.BindingContext[dgv.DataSource, dgv.DataMember]); if (cm.List is BindingSource) { // In case of BindingSource it may be chain of BindingSources+relations BindingSource bs = (BindingSource)cm.List; while (bs.List is BindingSource) { bs = bs.List as BindingSource; } if (bs.List is DataView) { dv = bs.List as DataView; } } else if (cm.List is DataView) { // dgv bind to the DataView, Table or DataSet+"tablename" dv = cm.List as DataView; } if (dv != null) { dv.Sort = "somedate desc, firstname"; // dv.Filter = "lastname = 'Smith' OR lastname = 'Doe'"; // You can Set the Glyphs something like this: int somedateColIdx = 5; // somedate int firstnameColIdx = 3; // firstname dgv.Columns[somedateColIdx].HeaderCell.SortGlyphDirection = SortOrder.Descending; dgv.Columns[firstnameColIdx].HeaderCell.SortGlyphDirection = SortOrder.Ascending; } 

注意: Sort和Filter中使用的列名称对应于DataTable中的列名称,DataGridView中的列名称是用于绑定的基础数据属性名称(类的属性名称,DataTables的列名称等)。 您可以像这样获取DataView中使用的列名:

 string colName = dgv.Columns[colIdx].DataPropertyName 

取决于您如何跟踪排序列(colSequence,colName,asc / desc,dgvColIdx),您可以决定如何构建Sort和Filter表达式并在dgv中设置SortGlyph(为简单起见,我制作了硬编码)。

好。

根据Cody的上述建议,我现在有了一些似乎按预期工作的东西。 我已经对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() .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() .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(this IEnumerable value, Action action) { foreach (T item in value) { action(item); } } } } 

我从来没有在这里回答过一个问题,所以如果格式不正确我会道歉,但我找到了这个问题的答案,这对未来的访问者来说可能更简单。 (见http://www.pcreview.co.uk/threads/datagridview-glyphs.3145090/ )

 Dim dictionarySortColumns As New Dictionary(Of String, Integer) Private Sub DataGridViewFileLoader_Sorted(sender As Object, e As EventArgs) Handles DataGridViewFileLoader.Sorted Dim dv As New DataView(dataSetLoadScreener.Tables(0)) Dim columnHeader As String = DataGridViewFileLoader.SortedColumn.Name Dim sortDirection As Integer = DataGridViewFileLoader.SortOrder Dim sortcode As String = "" Dim sortOrder As String = "" If sortDirection = 1 Then sortOrder = "ASC" Else sortOrder = "DESC" End If If dictionarySortColumns.ContainsKey(columnHeader) Then dictionarySortColumns.Remove(columnHeader) End If sortcode = columnHeader + " " + sortOrder For Each colHeader As String In dictionarySortColumns.Keys If dictionarySortColumns(colHeader) = 1 Then sortOrder = "ASC" Else sortOrder = "DESC" End If sortcode = sortcode + "," + colHeader + " " + sortOrder Next dictionarySortColumns.Add(columnHeader, sortDirection) dv.Sort = sortcode DataGridViewFileLoader.DataSource = Nothing DataGridViewFileLoader.DataSource = dv formatDataGridViewFileLoader() End Sub Private Sub DataGridViewFileLoader_CellPainting(sender As Object, e As DataGridViewCellPaintingEventArgs) Handles DataGridViewFileLoader.CellPainting Dim sOrder As System.Windows.Forms.SortOrder For Each key As String In dictionarySortColumns.Keys If dictionarySortColumns(key) = 1 Then sOrder = Windows.Forms.SortOrder.Ascending Else sOrder = Windows.Forms.SortOrder.Descending End If DataGridViewFileLoader.Columns(key).HeaderCell.SortGlyphDirection = sOrder Next End Sub