替换巨大的 DataGridViewComboBoxColumn 以提高性能

Replacing huge DataGridViewComboBoxColumn for performance

我有一个带有 WinForms DataGridView 的对话框,其中显示了一个用户列表。每行包含一个 AD-User 组合框 (DataGridViewComboboxColumn),它可以变得非常大(超过 10K 个项目)。 此 DataGridView 用于 link 用户及其相应的 AD 用户。此组合框的内容不会在行之间更改。

出于性能原因,我想将此组合框更改为可缩放的东西。

我正在考虑使用一个带有小选择按钮的文本框。然后该按钮将打开一个用于选择 AD 用户的模式对话框。然后该单元格将包含选定的 AD 用户对象。 或者,此对话框也可以通过双击单元格打开,但我认为这不是很直观。

这是替换此组合框的最佳选择吗?如果您有 other/better 种处理此类选择的方法,请告诉我。

如果是的话:如何创建这样一个自定义 DataGridView-Cell(文本框 + 按钮)?

最简单的解决方案是将列设置为只读,然后再使用按钮列。然后处理 DataGridViewCellContentClick 事件以检测按钮点击。

另一种选择是创建基于 DataGridViewButtonColumn 的自定义列。 稍作更改以显示单元格的值而不是标签文本。

您也可以在不创建任何新列类型的情况下通过自定义绘制单元格来实现它,

例子

我的选择来自 DataGridView 按钮列以获得更好的用户体验,例如在鼠标移动时突出显示按钮。为此,我将更改此 ,它展示了如何在单个单元格中呈现标签和按钮。在这里,我对其进行了一些更改,以将单元格值显示为标签文本:

using System.Drawing;
using System.Windows.Forms;
public class DataGridViewLookupColumn : DataGridViewButtonColumn
{
    public DataGridViewLookupColumn()
    {
        CellTemplate = new DataGridViewLookupCell();
        ButtonText = "...";
    }
    public string ButtonText { get; set; }
    public override object Clone()
    {
        var c = (DataGridViewLookupColumn)base.Clone();
        c.ButtonText = this.ButtonText;
        return c;
    }
}
public class DataGridViewLookupCell : DataGridViewButtonCell
{
    protected override void Paint(Graphics graphics, Rectangle clipBounds,
        Rectangle cellBounds, int rowIndex,
        DataGridViewElementStates elementState,
        object value, object formattedValue, string errorText,
        DataGridViewCellStyle cellStyle,
        DataGridViewAdvancedBorderStyle advancedBorderStyle,
        DataGridViewPaintParts paintParts)
    {
        var g = this.DataGridView;
        var c = (DataGridViewLookupColumn)this.OwningColumn;
        base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState,
            value, formattedValue, errorText, cellStyle, advancedBorderStyle,
            DataGridViewPaintParts.All &
            ~DataGridViewPaintParts.ContentBackground &
            ~DataGridViewPaintParts.ContentForeground);
        var cellRectangle = g.GetCellDisplayRectangle(c.Index, rowIndex, false);
        var buttonRectangle = GetContentBounds(rowIndex);
        var textRectangle = new Rectangle(cellRectangle.Location,
            new Size(cellRectangle.Width - GetButtonWidth(),
            cellRectangle.Height));
        buttonRectangle.Offset(cellRectangle.Location);
        var alignment = cellStyle.Alignment;
        cellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
        base.Paint(graphics, clipBounds, buttonRectangle, rowIndex, elementState,
            value, c.ButtonText, errorText, cellStyle, advancedBorderStyle,
            DataGridViewPaintParts.All &
            ~DataGridViewPaintParts.Border);
        cellStyle.Alignment = alignment;
        base.Paint(graphics, clipBounds, textRectangle, rowIndex, elementState,
             value, formattedValue, errorText, cellStyle, advancedBorderStyle,
             DataGridViewPaintParts.ContentForeground);
    }
    protected override Rectangle GetContentBounds(Graphics graphics,
        DataGridViewCellStyle cellStyle, int rowIndex)
    {
        var w = GetButtonWidth();
        var r = base.GetContentBounds(graphics, cellStyle, rowIndex);
        return new Rectangle(r.Right - w, r.Top, w, r.Height);
    }
    private int GetButtonWidth()
    {
        var c = (DataGridViewLookupColumn)this.OwningColumn;
        var text = c.ButtonText;
        return TextRenderer.MeasureText(text, c.DefaultCellStyle.Font).Width
            + 10 /*a bit padding */;
    }
}

处理按钮点击

要处理按钮上的点击,请像正常处理 DataGridViewColumnButton 一样处理 CellContentClick 并检查 e.RowIndex > -1e.ColumnIndex == your desired column index

void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
    //if click is on row header or column header, do nothing.
    if(e.RowIndex < 0 || e.ColumnIndex < 0)
        return;

    //Check if click is on specific column 
    if( e.ColumnIndex  == dataGridView1.Columns["specific column name"].Index)
    {
        //Put some logic here, for example show a dialog and use result.
    }
}