5

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:

  1. Why is CellValueNeed being repeatedly called for a partially visible column anyway? Perhaps I can fix the cause of this.

  2. 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;
    }
ManInMoon
  • 6,795
  • 15
  • 70
  • 133
  • 1
    Glad the answer was of use. Sometimes complicated is the only way, but the processing time should be fairly low for that kind of calculation, I'd keep an eye on memory usage just in case but you should be fine. – JoeTomks Jun 20 '18 at 13:52
  • 1
    It's really odd that CellValueNeeded doesn't do this by default. But thank you for the prompt. – ManInMoon Jun 20 '18 at 13:56
  • 1
    I agree, I remember reading an article discussing visual layering in the universal windows platform applications and it discussed this kind of situation. Wasn't a perfect explanation but they had some reason for allowing it to be called in situations like yours, but for the life of me I can't remember. – JoeTomks Jun 20 '18 at 14:01

1 Answers1

3

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.

JoeTomks
  • 3,243
  • 1
  • 18
  • 42