[ACCEPTED]-Horrible redraw performance of the DataGridView on one of my two screens-nvidia
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
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 });
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})
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();
}
}
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
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).
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.
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
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
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.