You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VB.NET中如何重写DataGridViewComboBoxColumn实现自定义交互

交互效果参考

实现方案

核心逻辑分三步实现:

  • 先将默认只读的ComboBox列改为可直接输入文本的模式
  • 拦截ComboBox下拉按钮的点击事件,屏蔽原生下拉菜单的弹出逻辑
  • 在拦截到点击动作时,将自定义Form定位到当前单元格下方弹出,选择完成后将结果回写到单元格即可

完整代码实现

首先自定义可拦截下拉、支持自由输入的编辑控件:

public class EditableComboEditingControl : ComboBox, IDataGridViewEditingControl
{
    private DataGridView _dataGridView;
    private int _rowIndex;
    private bool _valueChanged;
    private bool _dropDownHandled = false;

    public EditableComboEditingControl()
    {
        DropDownStyle = ComboBoxStyle.DropDown;
        // 拦截默认下拉事件
        DropDown += (s, e) =>
        {
            if (!_dropDownHandled)
            {
                e.Cancel = true;
                _dropDownHandled = true;
                
                // 替换为你自己的自定义选择窗体
                using (var customSelectForm = new YourCustomSelectionForm())
                {
                    // 计算窗体弹出位置,对齐单元格左下角
                    var currentCell = _dataGridView.CurrentCell;
                    var cellBounds = _dataGridView.GetCellDisplayRectangle(currentCell.ColumnIndex, currentCell.RowIndex, false);
                    var screenLocation = _dataGridView.PointToScreen(new Point(cellBounds.Left, cellBounds.Bottom));
                    
                    customSelectForm.StartPosition = FormStartPosition.Manual;
                    customSelectForm.Location = screenLocation;
                    customSelectForm.ShowInTaskbar = false;
                    customSelectForm.FormBorderStyle = FormBorderStyle.FixedToolWindow;

                    if (customSelectForm.ShowDialog() == DialogResult.OK)
                    {
                        // 回写选中值
                        Text = customSelectForm.SelectedResult?.ToString() ?? string.Empty;
                        _valueChanged = true;
                        _dataGridView.NotifyCurrentCellDirty(true);
                    }
                }
                _dropDownHandled = false;
            }
        };
    }

    // IDataGridViewEditingControl 接口标准实现
    public DataGridView EditingControlDataGridView
    {
        get => _dataGridView;
        set => _dataGridView = value;
    }

    public object EditingControlFormattedValue
    {
        get => Text;
        set => Text = value?.ToString() ?? string.Empty;
    }

    public int EditingControlRowIndex
    {
        get => _rowIndex;
        set => _rowIndex = value;
    }

    public bool EditingControlValueChanged
    {
        get => _valueChanged;
        set => _valueChanged = value;
    }

    public Cursor EditingPanelCursor => Cursors.Default;
    public bool RepositionEditingControlOnValueChange => false;

    public void ApplyCellStyleToEditingControl(DataGridViewCellStyle dataGridViewCellStyle)
    {
        Font = dataGridViewCellStyle.Font;
        ForeColor = dataGridViewCellStyle.ForeColor;
        BackColor = dataGridViewCellStyle.BackColor;
    }

    public bool EditingControlWantsInputKey(Keys keyData, bool dataGridViewWantsInputKey)
    {
        var key = keyData & Keys.KeyCode;
        return key is Keys.Left or Keys.Right or Keys.Up or Keys.Down or Keys.Home or Keys.End or Keys.Delete || !dataGridViewWantsInputKey;
    }

    public object GetEditingControlFormattedValue(DataGridViewDataErrorContexts context) => Text;

    public void PrepareEditingControlForEdit(bool selectAll)
    {
        if (selectAll) SelectAll();
    }

    protected override void OnTextChanged(EventArgs e)
    {
        base.OnTextChanged(e);
        _valueChanged = true;
        _dataGridView?.NotifyCurrentCellDirty(true);
    }
}

再配套自定义单元格和列类型:

public class EditableComboCell : DataGridViewComboBoxCell
{
    public override Type EditType => typeof(EditableComboEditingControl);
    public override Type ValueType => typeof(string);
    public override object DefaultNewRowValue => string.Empty;
}

public class EditableComboColumn : DataGridViewComboBoxColumn
{
    public EditableComboColumn()
    {
        CellTemplate = new EditableComboCell();
        DropDownStyle = ComboBoxStyle.DropDown;
    }
}

使用注意事项

  • 把DataGridView中原生的DataGridViewComboBoxColumn替换为上面实现的EditableComboColumn即可生效,用户可直接在单元格内输入任意文本
  • 自定义选择窗体可以根据需求实现搜索、多选、树形选择等任意逻辑,只要在确认选择后把结果赋值给窗体的SelectedResult属性即可自动回写到单元格
  • 如果需要实现点击窗体外自动关闭的效果,可以重写自定义窗体的WndProc方法,捕获非客户区的鼠标点击消息触发Close即可。

内容的提问来源于stack exchange,提问作者Senior Guru

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 16:33:26