5

I have a System.Windows.Forms DataGridView that is bound to a List<MyObject>.
The class MyObject contains a boolean property that is bound to DataGridViewCheckboxCell within the DataGridView.

public class MyObject
{
    public decimal DefaultValue {get; set; }
    public bool HasCustomValue {get;set; }
    public decimal CustomValue {get;set; }
    public decimal CurrentValue
    {
        get
        {
            return HasCustomValue
                ? CustomValue
                : DefaultValue;
        }
}

If I change the value of HasCustomValue another (readonly) property CurrentValue changes it's value, too. That is done by implementing the INotifyPropertyChanged event (I left that part in the source example for simplicity)

If I changed HasCustomValue from outside the DataGridView, the column bound to CurrentValue gets updated immediately. Howevery, If the users enables/disables the checkbox, HasCustomValue is not changed in the underlying datasource unless he leaves the column by clicking with the mouse or pressing the TAB key.

Is there a way to force the grid to update the datasource directly after changing a checkbox value?

If I bind a Control Property I have the ability to set the DataSourceUpdateMode to Windows.Forms.DataSourceUpdateMode.OnPropertyChanged but I haven't found anything like that in a DataGridView

Jürgen Steinblock
  • 30,746
  • 24
  • 119
  • 189
  • Can you show the DataGridView markup? – jcolebrand Jan 03 '11 at 16:44
  • It's WinForms, so I have no markup code ;) – Jürgen Steinblock Jan 03 '11 at 19:44
  • I seriously can't think of any element in C# that doesn't have either code or markup. It may be a visual designer, but there's still code. Are you sure there's no markup code? – jcolebrand Jan 03 '11 at 21:54
  • I wouldn't name the designer code markup code http://en.wikipedia.org/wiki/Markup_language Anyway, I haven't set any special properties, just added a CheckBox column to the DataGridView and some textbox columns, too. I suppose I will follow alliswell's suggestion and handle the Click event. – Jürgen Steinblock Jan 07 '11 at 14:26

5 Answers5

2

I had a similar problem. And I wasn't using a BindingSource, just a BindingList. After lots of frustration and experimentation (and following different solutions that didn't quite work),

I simply did this:

  • override the DataGridView's CellMouseUp event
  • in the event, call the DataGridView's EndEdit() method.
Shakti Prakash Singh
  • 2,414
  • 5
  • 35
  • 59
Rob Bryce
  • 261
  • 2
  • 7
2

I did this trick:

  • Set the column's with CheckBox ReadOnly property to true.
  • Then in CellContentClick event handler programmatically change the value to its opposite value.

    private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
    {
        int chkBoxColIdx = 0; //Index of the column with checkbox.
        if (e.ColumnIndex == chkBoxColIdx)
        {
            dataGridView1.Rows[e.RowIndex].Cells[chkBoxColIdx].Value = !(bool)dataGridView1.Rows[e.RowIndex].Cells[chkBoxColIdx].Value;
        }
    
Szybki
  • 1,083
  • 14
  • 29
  • Setting the column property to read only worked for me, too, with code put in the OnClick event. Use the InvalidateCell method on the DataGridView, then set the cell value, – subjectivist Sep 25 '15 at 19:39
2

I assume you are using bindingsource then on Check Box Click event/Edited do the ,

    BindingSource.EndEdit()
indiPy
  • 7,844
  • 3
  • 28
  • 39
1

Use handler for datagridview.CurrentCellDirtyStateChanged

private void datagridview_CurrentCellDirtyStateChanged(Object sender, EventArgs e)
{
    //_checkboxColumnIndex - index of your checkboxcolumn
    DataGridView dgv = (DataGridView)sender;
    if (_checkboxColumnIndex == dgv.CurrentCell.ColumnIndex &&
        dgv.Columns[_checkboxColumnIndex].GetType() == typeof(DataGridViewCheckBoxColumn) &&
        dgv.IsCurrentCellDirty == true)
    {          
        //Remember that here dgv.CurrentCell.Value is previous/old value yet
        YourObject.HasCustomValue = !(bool)dgv.CurrentCell.Value
    }

    dgv.CommitEdit(DataGridViewDataErrorContexts.Commit) //this will fire .CellEndEdit event
}
Fabio
  • 31,528
  • 4
  • 33
  • 72
  • This works for me, although the `EventArgs` object does not have an `e.ColumnIndex`. You can use `dgv.CurrentCell.ColumnIndex` instead of `e.ColumnIndex`. – Mark Hildreth Mar 03 '14 at 22:59
1

I can imagine that you don't want your bindingSource know to what it is bound to. After all, isn't that why you created a bindingSource: to be able to let it be bound to bound to virtually anything.

So naturally, you don't want to know how the value of your current item is changed; you only want to know that it has been changed.

For this you use event BindingSource.CurrentItemChanged: whatever method is used to change the data, you get notified.

The view that is bound to the BindingSource has to tell the BindingSource that changing the value is finished; editing the property has ended.

In your case the view is a DataGridView. A DataGridView tells the BindingSource that the current cell has finished changing using DataGridView.EndEdit().

Normally while you are typing the cell, the editing is ended when the cell loses focus, or when you press esc. This gives you the opportunity to correct typing errors or cancel editing in case you don't want the changes.

However in case of a DataGridViewCheckBoxCell most people expect to finish editing as soon as the DataGridviewCheckBoxCell is clicked.

Therefore you need to handle event DataGridView.CurrentCellDirtyStateChanged

// Whenever a DataGridViewCheckBoxCell becomes dirty editing is finished:
private void OnCurrentCellDirtyChanged(object sender, EventArgs e)
{
    if (this.dataGridView1.CurrentCell is DataGridViewCheckBoxCell;
    {
        this.dataGridView1.EndEdit();
    }
}

This will lead to event BindingSource.CurrentItemChanged

Harald Coppoolse
  • 28,834
  • 7
  • 67
  • 116