Windows 窗体 DataGridView 控件中的列排序模式
对同时包含绑定列和未绑定列的 DataGridView 控件进行排序时,无法自动维护未绑定列中的值。要维护这些值,您必须通过将 VirtualMode 属性设置为 true 并处理 CellValueNeeded 和 CellValuePushed 事件来实现虚拟模式。
这有点复杂,所以最简单的解决方案是在 DataTable 中添加一个额外的列。
我将在下面留下一个示例以供将来参考。
要点是:
VirtualMode
应该是真的。
CellValueNeeded
应正确处理以显示指定的单元格值。
ColumnHeaderMouseClick
应该正确处理以按未绑定的列排序,并显示排序字形。
笔记:
- 此示例中的 DataGridView 是只读的,以使事情变得简单。
此示例表单包含:
一个类型化的数据集,具有(string), (string)DataTable1
列: ID
Comment
private DataSet1 dataSet1;
一个绑定源:
private BindingSource dataTable1BindingSource;
.DataMember = "DataTable1";
.DataSource = this.dataSet1;
一个数据网格视图:
private DataGridView dataTable1DataGridView;
.DataSource = this.dataTable1BindingSource;
.VirtualMode = true;
.CellValueNeeded += this.dataTable1DataGridView_CellValueNeeded;
.ColumnHeaderMouseClick += this.dataTable1DataGridView_ColumnHeaderMouseClick;
.ReadOnly = true;
.AllowUserToAddRows = false;
.AllowUserToDeleteRows = false;
它的列:
private DataGridViewTextBoxColumn iDDataGridViewTextBoxColumn; // bound column
private DataGridViewTextBoxColumn commentDataGridViewTextBoxColumn; // bound column
private DataGridViewLinkColumn linkColumn; // unbound column
.SortMode = DataGridViewColumnSortMode.Automatic;
代码如下:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
// Hold the link texts, in a dictinary
// keyed by ID (= unique key in DataTable1), to be bound to each row.
private SortedDictionary<string, string> _linkTexts
= new SortedDictionary<string, string>();
private void Form1_Load(object sender, EventArgs e)
{
// Bound data sample
this.dataSet1.DataTable1.AddDataTable1Row("1", "Comment1");
this.dataSet1.DataTable1.AddDataTable1Row("2", "Comment2");
this.dataSet1.DataTable1.AddDataTable1Row("3", "Comment3");
// Unbound data sample
this._linkTexts.Add("1", "linkA");
this._linkTexts.Add("2", "linkC");
this._linkTexts.Add("3", "linkB");
}
// Handles ColumnHeaderMouseClick to do custom sort.
private void dataTable1DataGridView_ColumnHeaderMouseClick(
object sender, DataGridViewCellMouseEventArgs e)
{
// When the unbound column header is clicked,
if (e.ColumnIndex == this.linkColumn.Index)
{
// Create a new DataView sorted by the link text
// with toggling the sort order.
DataView newView;
switch (this.linkColumn.HeaderCell.SortGlyphDirection)
{
case SortOrder.None:
case SortOrder.Descending:
this.linkColumn.HeaderCell.SortGlyphDirection
= SortOrder.Ascending;
newView = this.dataSet1.DataTable1
.OrderBy(row => this._linkTexts[row.ID])
.AsDataView();
break;
default:
this.linkColumn.HeaderCell.SortGlyphDirection
= SortOrder.Descending;
newView = this.dataSet1.DataTable1
.OrderByDescending(row => this._linkTexts[row.ID])
.AsDataView();
break;
}
// Set it as DataSource.
this.dataTable1BindingSource.DataSource = newView;
// Clear sort glyphs on the other column headers.
foreach (DataGridViewColumn col
in this.dataTable1DataGridView.Columns)
{
if (col != this.linkColumn)
col.HeaderCell.SortGlyphDirection = SortOrder.None;
}
}
// The bound column header is clicked,
else
{
// Sorting has done automatically.
// Reset the sort glyph on the unbound column.
this.linkColumn.HeaderCell.SortGlyphDirection = SortOrder.None;
}
}
// Handles CellValueNeeded to show cell values in virtual mode.
private void dataTable1DataGridView_CellValueNeeded(
object sender, DataGridViewCellValueEventArgs e)
{
// Extract the bound row from the current data view.
DataSet1.DataTable1Row row
= (this.dataTable1BindingSource[e.RowIndex] as DataRowView)
.Row as DataSet1.DataTable1Row;
// For the unbound column,
if (e.ColumnIndex == this.linkColumn.Index)
{
if (row.IsIDNull())
e.Value = DBNull.Value;
else
// get the value from the dictionary.
e.Value = this._linkTexts[row.ID];
}
// For the bound columns,
else
{
// get the value from the data source.
string propName = this.dataTable1DataGridView
.Columns[e.ColumnIndex].DataPropertyName;
e.Value = row[propName];
}
}
}