I've only used virtual mode with DataGridView, but in virtual mode you are supposed to store the data yourself and provide it when the datagrid needs to for rendering. I suppose the datagrid is only creating the minimum number of items that is needed to fill the view and then reuse them for performance reasons.
This looks sort of like a threading problem to me. Are you using a BackgroundWorker or something similar to populate the _items variable? It looks like the number of things in _items is changing while you are looping over it.
Perhaps you could try surround any and all code dealing with _items with this:
lock (_items)
{
// your code
}
Alternatively, break out of these functions and return null if your population/alteration code is still running (use some kind of boolean sentinel variable perhaps).
How have you set up your databinding.
Would it be possible for you to work against the underlying dataset instead of going via the datagrid.
Just be aware of DataGridView's virtual mode limitations. Despite of its supposed low-memory consumption feature (only visible rows gets loaded from database); each row has their own instance (to prove, try to resize each of DataGridView rows, rows' sizes can be set independently of each other, thus each row's information(e.g. RowHeight) need be saved in their own memory)
When you set the RowCount, it will instantiate n number of rows from what you specified in RowCount. Thus defeating one of the original purposes of DataGridView's virtual mode, low-memory consumption. Too much memory consumption could slow down your datagrid display
See my article here http://www.codeproject.com/KB/grid/DataGridView_Billion_Rows.aspx, and the other article http://social.msdn.microsoft.com/Forums/en-US/winformsdatacontrols/thread/243a81e7-909b-4c8e-9d28-6114248cf66e