首页 > 解决方案 > 以编程方式添加到 DataGridView 单元格的 ComboBox 未在单元格单击时展开

问题描述

我在 C# WinForms 项目中有一个 DataGridView,其中,当用户单击某些 DGV 单元格时,单元格更改为 aDataGridViewComboBoxCell并且 ComboBox 填充了一些值供用户选择。这是 DataGridView_Click 事件的表单代码:

private void dgvCategories_Click(Object sender, DataGridViewCellEventArgs e)
{
    if (e.ColumnIndex == 5 && !(dgvCategories.Rows[e.RowIndex].Cells[e.ColumnIndex].GetType().Name == "DataGridViewComboBoxCell"))
    {
        // Bind combobox to dgv and than bind new values datasource to combobox
        DataGridViewComboBoxCell cboNewValueList = new DataGridViewComboBoxCell();

        // Get fields to build New Value query
        List<string> lsNewValuesResult = new List<string>();
        string strCategory = dtCategories.Rows[e.RowIndex][1].ToString();
        string strCompanyName = cboSelectCompany.Text;
        string strQueryGetNewValuesValidationInfo = "SELECT validationdb, validationtable, validationfield, validationfield2, validationvalue2" +
                                                " FROM masterfiles.categories" +
                                                " WHERE category = @category";
                                                //" WHERE category = '" + strCategory + "'";

        // Pass validation info query to db and return list of New Values
        db getListOfNewValues = new db();
        lsNewValuesResult = getListOfNewValues.GetNewValuesList(strQueryGetNewValuesValidationInfo, strCategory, strCompanyName);

        //Populate the combobox with the list of New Values
        foreach (string strListItem in lsNewValuesResult)
        {
            cboNewValueList.Items.Add(strListItem);
        }

        // 
        dgvCategories[e.ColumnIndex, e.RowIndex] = cboNewValueList;

    }
}

这是填充 ComboBox 的 db 类中的代码(出于此问题的目的,这可能没有必要包含,但为了完整起见,我将其包含在内,以防它相关):

public List<string> GetNewValuesList(string strValidationInfoQuery, string strCategory, string strCompanyName)
{
    List<string> lsValidationInfo = new List<string>();
    List<string> lsNewValuesList = new List<string>();

    using (NpgsqlConnection conn = new NpgsqlConnection(connString))
    using (NpgsqlCommand cmd = new NpgsqlCommand(strValidationInfoQuery, conn))
    {
        cmd.Parameters.AddWithValue("category", strCategory);

        conn.Open();

        using (NpgsqlDataReader reader = cmd.ExecuteReader())
        {
            while (reader.Read())
            {
                int intReaderIndex;
                for (intReaderIndex = 0; intReaderIndex <= reader.FieldCount - 1; intReaderIndex++)
                {

                    // reader indexes 3 & 4 correspond to categories.validationfield2 and validationvalue2, which can be null
                    if (string.IsNullOrEmpty(reader[intReaderIndex].ToString()))
                    {
                        lsValidationInfo.Add("");
                    }
                    else
                    {
                        lsValidationInfo.Add(reader.GetString(intReaderIndex));
                    }
                    //Console.WriteLine("reader index " + intReaderIndex + ": " + reader.GetString(intReaderIndex));
                }
            }
        }
    }

    string strValidationDb = lsValidationInfo[0];
    string strValidationTable = lsValidationInfo[1];
    string strValidationField = lsValidationInfo[2];
    string strValidationField2 = lsValidationInfo[3];
    string strValidationValue2 = lsValidationInfo[4];

    string strQueryGetNewValues = "SELECT DISTINCT " + strValidationField +
                        " FROM " + strValidationDb + "." + strValidationTable +
                        " WHERE company_id = (SELECT id FROM company WHERE name = '" + strCompanyName + "')";

    if (!string.IsNullOrEmpty(strValidationField2) && !string.IsNullOrEmpty(strValidationValue2)) strQueryGetNewValues += " AND " + strValidationField2 + " = '" + strValidationValue2 + "'";

    strQueryGetNewValues += " ORDER BY " + strValidationField;

    using (NpgsqlConnection conn = new NpgsqlConnection(connString))
    using (NpgsqlCommand cmd = new NpgsqlCommand(strQueryGetNewValues, conn))
    {
        conn.Open();

        using (NpgsqlDataReader reader = cmd.ExecuteReader())
        {
            while (reader.Read())
            {
                int intReaderIndex;
                for (intReaderIndex = 0; intReaderIndex <= reader.FieldCount - 1; intReaderIndex++)
                {
                    // reader indexes 3 & 4 correspond to categories.validationfield2 and validationvalue2, which can be null
                    if (string.IsNullOrEmpty(reader[intReaderIndex].ToString()))
                    {
                        lsNewValuesList.Add("");
                    }
                    else
                    {
                        lsNewValuesList.Add(reader.GetString(intReaderIndex));
                    }
                    Console.WriteLine("reader index " + intReaderIndex + ": " + reader.GetString(intReaderIndex));
                }
            }
        }
    }

    return lsNewValuesList;
}

组合框正在填充,因为我可以访问方法lsNewValuesResult中的项目_Click。DGV 编辑模式设置为EditOnEnter。我试过EditOnKeystroke了,但这并没有导致组合框在鼠标点击时展开。

这是单击单元格并填充 CBO 并将其添加到 DGV 单元格时组合框的外观:

在此处输入图像描述

那是在我单击两个单元格中的每一个之后。

[解决]

请参阅下面的我的答案。

不幸的是,解决这个问题揭示了一个新问题

标签: c#winformsdatagridviewdatagridviewcomboboxcell

解决方案


如果我正确识别您的问题,在我的测试应用程序中添加一个DataGridViewwhit 6 列,EditMode = EditOnEnter (其他需要三次单击以打开下拉列表, 据我尝试)并处理CellStateChanged事件。

private void dgvCategories_CellStateChanged(object sender, DataGridViewCellStateChangedEventArgs e)
{
    if (e.StateChanged == DataGridViewElementStates.Selected)
    {
        DataGridViewCell cell = e.Cell;
        int columnIndex = cell.ColumnIndex;
        int rowIndex = cell.RowIndex;
        //---IF CONDITIONS--
        //columnIndex == 5
        //          Only cells in Columns[5]
        //cell.Selected
        //          Because this event raised two time, first for last selected cell and once again
        //          for currently selected cell and we need only currently selected cell.
        //cell.EditType.Name != "DataGridViewComboBoxEditingControl"
        //          If this cell "CellStateChanged" raised for second time, only other cell types allowed
        //          to edit, otherwise the current cell lost last selected item.
        if (columnIndex == 5 && cell.Selected && cell.EditType.Name != "DataGridViewComboBoxEditingControl")
        {
            DataGridViewComboBoxCell cboNewValueList = new DataGridViewComboBoxCell();

            //Add items to DataGridViewComboBoxCell for test, replace it with yours.
            for (int i = 0; i < 10; i++)
                cboNewValueList.Items.Add($"Item {i}");

            dgvCategories[columnIndex, rowIndex] = cboNewValueList;
        }
    }
}

注意:用户必须在单元格中单击两次才能打开下拉菜单。

编辑一:正如 Reza Aghaei 建议在单元格中单击:

private void dgvCategories_CellClick(object sender, DataGridViewCellEventArgs e)
{
    DataGridViewComboBoxEditingControl editingControl = dgvCategories.EditingControl as DataGridViewComboBoxEditingControl;
    if (editingControl != null)
        editingControl.DroppedDown = true;
}

推荐阅读