ComboBox, программно добавленный в DataGridView, не открывается до тех пор, пока ячейка не потеряет фокус, а затем снова нажата - PullRequest
0 голосов
/ 15 апреля 2020

В проекте C# WinForms я заполняю DGV из DataTable. Когда пользователь нажимает на ячейку одного из столбцов, мне нужно заполнить ComboBox и открыть его одним щелчком мыши .

Однако CBO открывается только тогда, когда соответствующая ячейка теряет фокус (щелкните где-нибудь еще в форме), а затем возвращает фокус (снова щелкните в этой ячейке) - и только если нажата стрелка CBO вниз, а не если текст CBO щелкнут. Мне также нужно, чтобы CBO открывался при нажатии на текст CBO.

private void dgvCategories_Click(Object sender, DataGridViewCellEventArgs e)
{
    try
    {
        // Prevent code from executing if user clicks on a cell that already has a CBO
        if (e.ColumnIndex == 5 && !(dgvCategories.Rows[e.RowIndex].Cells[e.ColumnIndex].GetType().Name == "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";

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

            // Create CBO object
            DataGridViewComboBoxCell cboNewValueList = new DataGridViewComboBoxCell();

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

            // Bind the CBO to the DGV
            dgvCategories[e.ColumnIndex, e.RowIndex] = cboNewValueList;

            var editingControl = dgvCategories.EditingControl as DataGridViewComboBoxEditingControl;
            if (editingControl != null) editingControl.DroppedDown = true;
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine("dgvCategories_Click Exception: " + ex.Message);
    }

}

DataGridViewEditMode установлен на EditOnEnter, а DataGrieViewSelectionMode установлен на CellSelect.

. две строки в конце взяты из SO Вопрос: « DataGridViewComboBoxColumn - нужно дважды щелкнуть ячейку, чтобы отобразить поле со списком "

Я не уверен, что еще попробовать ...

1 Ответ

0 голосов
/ 20 апреля 2020

Если вы решили использовать событие CellBeginEdit для решения вашей проблемы, то вы можете использовать следующий подход:

Вот объяснение этого подхода:

  • if CellBeginEdit событие происходит в ячейке типа TextBox, мы отменяем это событие, а затем:
    • меняем тип текущей ячейки на ComboBox;
    • запускаем CellBeginEdit событие для текущего ComboBox cell;
    • автоматически сбрасывает текущую ComboBox ячейку;
  • , если в ячейке типа ComboBox происходит событие CellBeginEdit, мы просто выпадаем из нее;
  • мы используем BeginInvoke, чтобы изменить тип текущей ячейки и затем начать редактирование, потому что:
    • существует известная проблема с DataGridView (
1 , 2 ), который заставляет нас использовать BeginInvoke: тип ячейки изменяется при завершении события CellBeginEdit.

Подход CellBeginEdit также имеет следующее преимущество: он меняет тип ячейки, либо пользователь перемещается к ячейке с помощью мыши или клавиатуры.


Другой подход заключается в использовать CellStateChanged событие:

private void dgvCategories_CellStateChanged(object sender, DataGridViewCellStateChangedEventArgs e)
{
    if (e.StateChanged == DataGridViewElementStates.Selected)
    {
        int col = e.Cell.ColumnIndex;
        int row = e.Cell.RowIndex;

        if (col == 5)
        {
            if (dgvCategories.Rows[row].Cells[col].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 = getCboValues();

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

                // 
                cboNewValueList.Value = dgvCategories[col, row].Value;
                dgvCategories[col, row] = cboNewValueList;

                // To drop down current cell we must call BeginInvoke,
                // because in the CellStateChanged event handler
                // dgvCategories.EditingControl is null.
                BeginInvoke(new Action(
                    () =>
                    {
                        if (dgvCategories.EditingControl != null)
                            ((DataGridViewComboBoxEditingControl) dgvCategories.EditingControl).DroppedDown = true;
                    }));
            }
            else
            {
                // If current cell is already ComboBox we simply drop it down.
                BeginInvoke(new Action(
                    () =>
                    {
                        if (dgvCategories.EditingControl != null)
                            ((DataGridViewComboBoxEditingControl)dgvCategories.EditingControl).DroppedDown = true;
                    }));
            }
        }
    }
}
...