Showing posts with label DataGridView. Show all posts
Showing posts with label DataGridView. Show all posts

Thursday, October 21, 2010

DataGridView virtual mode with custom control race condition fix

This is for when you have a DataGridView in virtual mode in which you have both unbound and bound columns which depend on each other. It went wrong when editing the cells.
I found out that I got a race condition. I then checked the stacktrace:

- MyGridView.OnCellValueNeeded(System.Windows.Forms.DataGridViewCellValueEventArgs e)
- System.Windows.Forms.DataGridView.OnCellValueNeeded(int columnIndex, int rowIndex)
- System.Windows.Forms.DataGridViewCell.GetValue(int rowIndex)
- DataGridViewControlCell.GetValue(int rowIndex)
- System.Windows.Forms.DataGridView.OnCellValidating(ref System.Windows.Forms.DataGridViewCell dataGridViewCell, int columnIndex, int rowIndex, System.Windows.Forms.DataGridViewDataErrorContexts context)
- System.Windows.Forms.DataGridView.CommitEdit(ref System.Windows.Forms.DataGridViewCell dataGridViewCurrentCell, System.Windows.Forms.DataGridViewDataErrorContexts context, System.Windows.Forms.DataGridView.DataGridViewValidateCellInternal validateCell, bool fireCellLeave, bool fireCellEnter, bool fireRowLeave, bool fireRowEnter, bool fireLeave)
- System.Windows.Forms.DataGridView.CommitEdit(System.Windows.Forms.DataGridViewDataErrorContexts context, bool forCurrentCellChange, bool forCurrentRowChange)



So it tried getting the value for the cell that was currently being edited !
I fixed it in MyGridView (called with base.OnCellValueNeeded):

        protected override void OnCellValueNeeded(DataGridViewCellValueEventArgs e)
        {
            if (Columns[e.ColumnIndex] is DataGridViewControlColumn)
            {
                /*
                 * Special check to prevent race condition. Call this method first like this:
                 *    base.OnCellValueNeeded(e);
                 *    if (e.Value != null) return;
                 */
                if (Rows[e.RowIndex].Cells[e.ColumnIndex].IsInEditMode)        // editing control present?
                {
                    if ((EditingControl as TControl).EditingControlRowIndex == e.RowIndex)        // make sure it's the correct row
                    {
                        if ((EditingControl as TControl).EditingControlValueChanged)    // prevent re-use of old editing control
                        {
                            e.Value = (EditingControl as TControl).EditingControlFormattedValue;    // use value from editing control
                            return;
                        }
                    }
                }
            }
             base.OnCellValueNeeded(e);
        }

 Hopefully, you find this a bit useful.