bitbonk
bitbonk

Reputation: 49619

Apply and validate a bound DataGridViewComboBoxCell directly upon selection change

I have a windows forms DataGridView that contains some DataGridViewComboBoxCells that are bound to a source collection using DataSource, DisplayMember and ValueMember properties. Currently the the combobox cell commits the changes (i.e. DataGridView.CellValueChanged is raised) only after I click on another cell and the combobox cell loses focus.

How would I ideally commit the change directly after a new value was selected in the combobox.

Upvotes: 3

Views: 1725

Answers (3)

Danny
Danny

Reputation: 489

A better way to achieve this that I am using successfully rather than subclassing or the somewhat inelegant binding source method above, is the following (sorry it's VB but if you can't translate from VB to C# you have bigger problems :)

Private _currentCombo As ComboBox

Private Sub grdMain_EditingControlShowing(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewEditingControlShowingEventArgs) Handles grdMain.EditingControlShowing
    If TypeOf e.Control Is ComboBox Then
        _currentCombo = CType(e.Control, ComboBox)
        AddHandler _currentCombo.SelectedIndexChanged, AddressOf SelectionChangedHandler
    End If
End Sub

Private Sub grdMain_CellEndEdit(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles grdMain.CellEndEdit
    If Not _currentCombo Is Nothing Then
        RemoveHandler _currentCombo.SelectedIndexChanged, AddressOf SelectionChangedHandler
        _currentCombo = Nothing
    End If
End Sub

Private Sub SelectionChangedHandler(ByVal sender As Object, ByVal e As System.EventArgs)
    Dim myCombo As ComboBox = CType(sender, ComboBox)
    Dim newInd As Integer = myCombo.SelectedIndex

    //do whatever you want with the new value

    grdMain.NotifyCurrentCellDirty(True)
    grdMain.CommitEdit(DataGridViewDataErrorContexts.Commit)
End Sub

That's it.

Upvotes: 0

Don Kirkby
Don Kirkby

Reputation: 56650

I tried using Bradley's suggestion, but it was sensitive to when you attached the cell template. It seemed like I couldn't allow the design view to wire up the column, I had to do it myself.

Instead, I used the binding source's PositionChanged event, and triggered updates from that. It's a little bit odd, because the control is still in edit mode, and the databound object doesn't get the selected value yet. I just updated the bound object myself.

    private void bindingSource_PositionChanged(object sender, EventArgs e)
    {
        (MyBoundType)bindingSource.Current.MyBoundProperty = 
            ((MyChoiceType)comboBindingSource.Current).MyChoiceProperty;
    }

Upvotes: 0

Bradley Smith
Bradley Smith

Reputation: 13601

This behaviour is written into the implementation of the DataGridViewComboBoxEditingControl. Thankfully, it can be overridden. First, you must create a subclass of the aforementioned editing control, overriding the OnSelectedIndexChanged method:

protected override void OnSelectedIndexChanged(EventArgs e) {
    base.OnSelectedIndexChanged(e);

    EditingControlValueChanged = true;
    EditingControlDataGridView.NotifyCurrentCellDirty(true);
    EditingControlDataGridView.CommitEdit(DataGridViewDataErrorContexts.Commit);
}

This will ensure that the DataGridView is properly notified of the change in item selection in the combo box when it takes place.

You then need to subclass DataGridViewComboBoxCell and override the EditType property to return the editing control subclass from above (e.g. return typeof(MyEditingControl);). This will ensure that the correct editing control is created when the cell goes into edit mode.

Finally, you can set the CellTemplate property of your DataGridViewComboBoxColumn to an instance of the cell subclass (e.g. myDataGridViewColumn.CellTemplate = new MyCell();). This will ensure that the correct type of cell is used for each row in the grid.

Upvotes: 1

Related Questions