I have a datagridview with VirtualMode = true that I have also implemented drag/drop to enable the user to reorder rows within the datagridview. My issue is even though I am using SuspendLayout/ResumeLayout, the datagridview is still calling CellValueNeeded in the middle of processing causing my program to crash.
Within the DragDrop event, I have the following code where 'dragRow' is the source row and 'row' is the destination of the drag/drop event.
gridview.SuspendLayout();
try
{
// copy dragged row
DataGridViewRow rowCopy = gridview.Rows[dragRow];
DataValue dataCopy = dataList[dragRow];
// remove dragged row
dataList.RemoveAt(dragRow);
gridview.Rows.RemoveAt(dragRow);
// insert row
dataList.Insert(row, dataCopy);
gridview.Rows.Insert(row, rowCopy);
// move selection to moved row
gridview.CurrentCell = gridview[gridview.CurrentCell.ColumnIndex, row];
}
finally { gridview.ResumeLayout(true); }
Before the drag/drop is initiated, my program detects that the user selected the last row. I have designed the last row to always be empty for reasons I am not going to get into here. Usually if the user selects the last row, then it initiates the drag/drop with only the DragDropEffects.Copy option enabled. If I detect the second to last row is also empty, then I switch the row being dragged to the second to last row to enable the user to move the blank row (as the last row is not movable). The issue is during the DragDrop event between where the row is removed from my data list to where it is inserted in the new location the datagridview calls its CellValueNeeded event causing my program to crash on an out of range exception as it tries to read something from my data list that is not there.
I have also seen this issue in relation to tool tips being displayed. If the user hovers the mouse within the row/cell they just dragged, then the tool tip displayed is for the wrong row as if the CellToolTipTextNeeded event was raised for the wrong cell and not updated after the ResumeLayout.
Is there something I'm missing that I should be doing to let the datagridview know I'm updating its data source while in virtualmode?
For reference, the following CellValueNeeded handler is example of where IndexOutOfRangeException is being thrown due to gridview trying to read from row that no longer exists in dataList after line dataList.RemoveAt(dragRow); in above code.
private void gridview_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
{
switch (e.ColumnIndex)
{
case 2: // Name
e.Value = dataList[e.RowIndex].Name;
break;
case 3: // Value
e.Value = dataList[e.RowIndex].Value;
break;
}
}