[ACCEPTED]-Horrible redraw performance of the DataGridView on one of my two screens-nvidia

Accepted answer
Score: 66

You just need to make a custom class based 16 off of DataGridView so you can enable its 15 DoubleBuffering. That's it!


class CustomDataGridView: DataGridView
{
    public CustomDataGridView()
    {
        DoubleBuffered = true;
    } 
}

As long as all 14 of my instances of the grid are using this 13 custom version, all is well. If I ever run 12 into a situation caused by this where I'm 11 not able to use the subclass solution (if 10 I don't have the code), I suppose I could 9 try to inject that control onto the form 8 :) (although I'll be more likely to try 7 using reflection to force the DoubleBuffered 6 property on from the outside to once again 5 avoid the dependency).

It is sad that such 4 a trivially simple thing ate up so much 3 of my time...

Note: Making the answer an 2 answer so the question can be marked as 1 answered

Score: 63

Here is some code that sets the property 2 using reflection, without subclassing as 1 Benoit suggests.

typeof(DataGridView).InvokeMember(
   "DoubleBuffered", 
   BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty,
   null, 
   myDataGridViewObject, 
   new object[] { true });
Score: 21

For people searching how to do it in VB.NET, here 1 is the code:

DataGridView1.GetType.InvokeMember("DoubleBuffered", Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Instance Or System.Reflection.BindingFlags.SetProperty, Nothing, DataGridView1, New Object() {True})
Score: 11

Adding to previous posts, for Windows Forms 10 applications this is what I use for DataGridView 9 components to make them fast. The code for 8 the class DrawingControl is below.

DrawingControl.SetDoubleBuffered(control)
DrawingControl.SuspendDrawing(control)
DrawingControl.ResumeDrawing(control)

Call DrawingControl.SetDoubleBuffered(control) after 7 InitializeComponent() in the constructor.

Call 6 DrawingControl.SuspendDrawing(control) before 5 doing big data updates.

Call DrawingControl.ResumeDrawing(control) after 4 doing big data updates.

These last 2 are 3 best done with a try/finally block. (or 2 even better rewrite the class as IDisposable and call 1 SuspendDrawing() in the constructor and ResumeDrawing() in Dispose().)

using System.Runtime.InteropServices;

public static class DrawingControl
{
    [DllImport("user32.dll")]
    public static extern int SendMessage(IntPtr hWnd, Int32 wMsg, bool wParam, Int32 lParam);

    private const int WM_SETREDRAW = 11;

    /// <summary>
    /// Some controls, such as the DataGridView, do not allow setting the DoubleBuffered property.
    /// It is set as a protected property. This method is a work-around to allow setting it.
    /// Call this in the constructor just after InitializeComponent().
    /// </summary>
    /// <param name="control">The Control on which to set DoubleBuffered to true.</param>
    public static void SetDoubleBuffered(Control control)
    {
        // if not remote desktop session then enable double-buffering optimization
        if (!System.Windows.Forms.SystemInformation.TerminalServerSession)
        {

            // set instance non-public property with name "DoubleBuffered" to true
            typeof(Control).InvokeMember("DoubleBuffered",
                                         System.Reflection.BindingFlags.SetProperty |
                                            System.Reflection.BindingFlags.Instance |
                                            System.Reflection.BindingFlags.NonPublic,
                                         null,
                                         control,
                                         new object[] { true });
        }
    }

    /// <summary>
    /// Suspend drawing updates for the specified control. After the control has been updated
    /// call DrawingControl.ResumeDrawing(Control control).
    /// </summary>
    /// <param name="control">The control to suspend draw updates on.</param>
    public static void SuspendDrawing(Control control)
    {
        SendMessage(control.Handle, WM_SETREDRAW, false, 0);
    }

    /// <summary>
    /// Resume drawing updates for the specified control.
    /// </summary>
    /// <param name="control">The control to resume draw updates on.</param>
    public static void ResumeDrawing(Control control)
    {
        SendMessage(control.Handle, WM_SETREDRAW, true, 0);
        control.Refresh();
    }
}
Score: 7

The answer to this worked for me too. I 10 thought I would add a refinement that I 9 think should be standard practise for anyone 8 implementing the solution.

The solution works 7 well except when the UI is being run as 6 a client session under remote desktop, especially 5 where the available network bandwidth is 4 low. In such a case, performance can be 3 made worse by the use of double-buffering. Therefore, I 2 suggest the following as a more complete 1 answer:

class CustomDataGridView: DataGridView
{
    public CustomDataGridView()
    {
        // if not remote desktop session then enable double-buffering optimization
        if (!System.Windows.Forms.SystemInformation.TerminalServerSession)
            DoubleBuffered = true;
    } 
}

For more details, refer to Detecting remote desktop connection

Score: 1

Just to add what we did to fix this issue: We 9 upgraded to the latest Nvidia drivers solved 8 the problem. No code had to be rewritten.

For 7 completeness, the card was an Nvidia Quadro 6 NVS 290 with drivers dated March 2008 (v. 169). Upgrading 5 to the latest (v. 182 dated Feb 2009) significantly 4 improved the paint events for all my controls, especially 3 for the DataGridView.

This issue was not 2 seen on any ATI cards (where development 1 occurs).

Score: 1

I found a solution to the problem. Go to 10 troubleshoot tab in the advanced display 9 properties and check the hardware acceleration 8 slider. When I got my new company PC from 7 IT, it was set to one tick from full and 6 I didn't have any problems with datagrids. Once 5 I updated the video card driver and set 4 it to full, painting of datagrid controls 3 became very slow. So I reset it back to 2 where it was and the problem went away.

Hope 1 this trick works for you as well.

Score: 1

Best!:

Private Declare Function SendMessage Lib "user32" _
  Alias "SendMessageA" _
  (ByVal hWnd As Integer, ByVal wMsg As Integer, _
  ByVal wParam As Integer, ByRef lParam As Object) _
  As Integer

Const WM_SETREDRAW As Integer = &HB

Public Sub SuspendControl(this As Control)
    SendMessage(this.Handle, WM_SETREDRAW, 0, 0)
End Sub

Public Sub ResumeControl(this As Control)
    RedrawControl(this, True)
End Sub

Public Sub RedrawControl(this As Control, refresh As Boolean)
    SendMessage(this.Handle, WM_SETREDRAW, 1, 0)
    If refresh Then
        this.Refresh()
    End If
End Sub

0

Score: 0

We've experienced a similar problem using 19 .NET 3.0 and DataGridView on a dual monitor 18 system.

Our application would display the 17 grid with a gray background, indicating 16 that the cells could not be changed. Upon 15 selecting a "change settings" button, the 14 program would change the background color 13 of the cells white to indicate to the user 12 that the cell text could be changed. A "cancel" button 11 would change the background color of the 10 aforementioned cells back to gray.

As the 9 background color changed there would be 8 a flicker, a brief impression of a default 7 sized grid with the same number of rows 6 and columns. This problem would only occur 5 on the primary monitor (never the secondary) and 4 it would not occur on a single monitor system.

Double 3 buffering the control, using the above example, solved 2 our problem. We greatly appreciated your 1 help.

More Related questions