I have a vertically and horizontally scrollable DataGridView on a form.
I use virtual mode because the underlying datatable is huge.
When I scroll right, if the last column is not fully shown in the view, then I see repeated calls to CellValueNeeded.
How can I fix this?
My thoughts:
Why is CellValueNeed being repeatedly called for a partially visible column anyway? Perhaps I can fix the cause of this.
Within CelValueNeeded - can I detect it is partially visible and return without processing? Both "Displayed" and "Visible" are true when I check the cell values.
My code:
private void grid_Data_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
{
Console.WriteLine("CellValue: " + e.RowIndex + " " + e.ColumnIndex);
if (e.RowIndex > Grid.Rows.Count - 1)
return;
DataGridView gridView = sender as DataGridView;
e.Value = Grid.Rows[e.RowIndex][e.ColumnIndex];
gridView.Rows[e.RowIndex].HeaderCell.Value = (e.RowIndex).ToString();
}
EDIT1:
After Digitalsa1nt's answer I found a way to fix the issue. It is complicated because the first column is treated differently to the last column. AND it makes a difference if you are setting RowHeaders.
In CellValueNeed above, I now return if the following function is true.
private bool IsPartiallyVisible(DataGridView gridView, DataGridViewCellValueEventArgs e)
{
if (gridView.FirstDisplayedScrollingColumnIndex == e.ColumnIndex)
{
if (gridView.FirstDisplayedScrollingColumnHiddenWidth != 0)
{
return true;
}
}
bool sameWidth = gridView.GetColumnDisplayRectangle(e.ColumnIndex, false).Width == gridView.GetColumnDisplayRectangle(e.ColumnIndex, true).Width;
return !sameWidth;
}
Looking at the MSDN documentation for CellValueNeeded
it reads as though it's a standard visual event, simply fires as soon as a cell becomes "visible", i don't think it defines the logic it uses to understand visual partiality. It just seems as though it tries to prepare for the cell to become fully "in-view". I suspect any intermediary states are not exposed.
That said there are some suggestions here (SO reply) and here (weird web-blog) that mention the use of DataGridView.GetColumnDisplayRectangle
with the intention of determining if the rectangle of the cell is within the bounds of the screen.
Here's a snippet from the web blog:
The second parameter to GetColumnDisplayRectangle is called CutOverFlow, which is a Boolean value that controls whether the function returns the complete column rectangle (even if the column is not completely visible) or only the portion of the column's rectangle that is visible.
By calling this method twice, once with CutOverFlow set to true and once with it set to false, you can create a function that compares the results and returns a Boolean value when the column is only partially visible:
Return dg.GetColumnDisplayRectangle(columnindex, False).Width = _
dg.GetColumnDisplayRectangle(columnindex, True).Width
This would allow you to stop processing when grid_Data_CellValueNeeded
is called and the above returns false based on the last cells location.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With