0
votes

I have a DataGridView control, whose first column is DataGridViewComboBoxColumn. Combox element has values let's say: "Custom","AAA","BBB". Second DataGridView column is just editable cells. When user selects any combobox item (except "Custom") user input is moved to the second column cell so he can write text.

What I want to achieve is that when user selects "Custom" then ComboBox value is editable so user can enter own value. I have tried using "OnCurrentCellDirtyStateChanged" and "EditingControlShowing" but this does not work. By "does not work" I mean that it actually sets this combobox to ComboBoxStyle.DropDown and I can edit this combobox item text only after I leave focus from the DataGridView row and then click with mouse on that combobox. But I need that it can be editable already after "Custom" is selected.

    public void typeColumnDataGridView_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
    {
        if (e.Control.GetType() == typeof(DataGridViewComboBoxEditingControl))
        {
            if (((ComboBox)e.Control).SelectedIndex == 0)
            {
                ((ComboBox)e.Control).DropDownStyle = ComboBoxStyle.DropDown;
            }
        }
    }

    public void typeColumnDataGridView_OnCurrentCellDirtyStateChanged(object sender, EventArgs e)
    {
        DataGridView dataGridView = sender as DataGridView;
        if (dataGridView == null || dataGridView.CurrentCell.ColumnIndex != 0) return;
        var dataGridViewComboBoxCell = dataGridView.CurrentCell as DataGridViewComboBoxCell;
        if (dataGridViewComboBoxCell != null)
        {
            if (dataGridViewComboBoxCell.FormattedValue != null)
            {
                if (dataGridViewComboBoxCell.FormattedValue.ToString() == "Custom")
                {
                    dataGridView.CurrentCell = dataGridView.Rows[dataGridView.CurrentCell.RowIndex].Cells[0];
                    dataGridView.BeginEdit(true); //This does not work
                    return;
                }
                else if (dataGridViewComboBoxCell.FormattedValue.ToString() == "")
                {
                    return;
                }
            }
        }
        dataGridView.CurrentCell = dataGridView.Rows[dataGridView.CurrentCell.RowIndex].Cells[1];
        dataGridView.BeginEdit(true);
    }
1
Simpler UI approach will be adding another column(TextBox). If Selected value of ComboBoxColumn is Custom - TextBoxColumn become editable, if not then value of Selected value of ComboBoxColumn copied to the TextBoxColumn.Fabio
Unfortunately this does not fit into design. The first column is a category and second column is a brief description, which is different each time.Vadim K.

1 Answers

1
votes

Okay, seems I've found a solution to my problem.

My logic thinking sequence was the following: Since editing of DataGridView combobox cell works only after losing focus and then clicking back on combobox, then I need to simulate this behavior programmatically.

So I modified "OnCurrentCellDirtyStateChanged" event as follows:

        public void typeColumnDataGridView_OnCurrentCellDirtyStateChanged(object sender, EventArgs e)
    {
        DataGridView dataGridView = sender as DataGridView;
        if (dataGridView == null || dataGridView.CurrentCell.ColumnIndex != 0) return;
        var dataGridViewComboBoxCell = dataGridView.CurrentCell as DataGridViewComboBoxCell;
        if (dataGridViewComboBoxCell != null)
        {
            if (dataGridViewComboBoxCell.EditedFormattedValue.ToString() == "Custom")
            {
                //Here we move focus to second cell of current row
                dataGridView.CurrentCell = dataGridView.Rows[dataGridView.CurrentCell.RowIndex].Cells[1];
                //Return focus to Combobox cell
                dataGridView.CurrentCell = dataGridView.Rows[dataGridView.CurrentCell.RowIndex].Cells[0];
                //Initiate Edit mode
                dataGridView.BeginEdit(true);
                return;
            }
        }
        dataGridView.CurrentCell = dataGridView.Rows[dataGridView.CurrentCell.RowIndex].Cells[1];
        dataGridView.BeginEdit(true);
    }

and also "EditingControlShowing" event:

        public void typeColumnDataGridView_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
    {
        if (e.Control.GetType() != typeof (DataGridViewComboBoxEditingControl)) return;
        if (((ComboBox) e.Control).SelectedIndex == 0)
        {
            //If user selected first combobox value "Custom", make control editable
            ((ComboBox) e.Control).DropDownStyle = ComboBoxStyle.DropDown;
        }
        else
        {
            if (((ComboBox) e.Control).DropDownStyle != ComboBoxStyle.DropDown) return;
            //If different value and combobox was set to editable, disable editing
            ((ComboBox) e.Control).DropDownStyle = ComboBoxStyle.DropDownList;
        }
    }

Added also "CellValidating" event to update Combobox values with custom typed value:

        public void typeColumnDataGridView_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
    {
        DataGridView dataGridView = sender as DataGridView;
        if (dataGridView == null) return;
        if (!dataGridView.CurrentCell.IsInEditMode) return;
        if (dataGridView.CurrentCell.GetType() != typeof (DataGridViewComboBoxCell)) return;
        DataGridViewComboBoxCell cell = (DataGridViewComboBoxCell)dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex];
        if (cell.Items.Contains(e.FormattedValue)) return;
        cell.Items.Add(e.FormattedValue);
        cell.Value = e.FormattedValue;
        if (((DataGridViewComboBoxColumn) dataGridView.Columns[0]).Items.Contains(e.FormattedValue)) return;
        ((DataGridViewComboBoxColumn)dataGridView.Columns[0]).Items.Add(e.FormattedValue);
    }