Pregunta

De hecho, he resuelto esto, pero voy a postear esto para la posteridad.

Me encontré con un extraño problema con el DataGridView en mi sistema de doble monitor.El problema se manifiesta a sí mismo como un EXTREMADAMENTE lenta actualización de la de control (como 30 segundos para un total de repintar), pero sólo cuando está en uno de mis pantallas.Cuando en el otro, el repaint de velocidad está muy bien.

Tengo una Nvidia 8800 GT con las últimas no-beta de los controladores (175.algo).Es un controlador de error?Se los dejo en el aire, ya que tengo que vivir con esta configuración particular.(Esto no sucede en las tarjetas ATI, aunque...)

La pintura de la velocidad no tiene nada que ver con el contenido de la celda, y la costumbre de dibujo no mejorar el rendimiento en todos - incluso cuando acaba de pintar un rectángulo sólido.

Yo más tarde se descubre que la colocación de un ElementHost (desde el Sistema.Windows.Los formularios.La integración del espacio de nombres) en el formulario se corrige el problema.No tiene que ser desordenado;sólo se necesita ser un hijo de la forma que el DataGridView es también.Se puede cambiar el tamaño a (0, 0) mientras que el Visible la propiedad es true.

No quiero agregar explícitamente el .NET 3/3.5 de la dependencia a mi solicitud;Hago un método para crear este control en tiempo de ejecución (si se puede) el uso de la reflexión.Funciona, y por lo menos falla correctamente en equipos que no disponen de la biblioteca - sólo vuelve a ser lento.

Este método también me permite aplicar para corregir mientras se ejecuta la aplicación, haciendo más fácil ver lo que el WPF las bibliotecas están cambiando en mi formulario (el uso de Spy++).

Después de un montón de prueba y error, me doy cuenta de que la habilitación de doble búfer en el control de sí mismo (como lo opuesto a la forma), se corrige el problema!


Por lo tanto, sólo necesita hacer una clase personalizada con sede fuera de DataGridView así que usted puede activar su DoubleBuffering.Eso es todo!

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

Mientras todos los de mi instancias de la cuadrícula están utilizando esta versión personalizada, todo está bien.Si alguna vez me encuentras en una situación causada por esta en que no me siento capaz de utilizar la subclase solución (si no tengo el código), supongo que yo podría tratar de inyectar ese control en el formulario :) (aunque voy a ser más propensos a probar el uso de la reflexión a la fuerza de la DoubleBuffered propiedad desde fuera, una vez más evitar la dependencia).

Es triste que un trivialmente simple cosa se comió gran parte de mi tiempo...

¿Fue útil?

Solución

Usted sólo necesita hacer una clase personalizada con sede fuera de DataGridView así que usted puede activar su DoubleBuffering.Eso es todo!


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

Mientras todos los de mi instancias de la cuadrícula están utilizando esta versión personalizada, todo está bien.Si alguna vez me encuentras en una situación causada por esta en que no me siento capaz de utilizar la subclase solución (si no tengo el código), supongo que yo podría tratar de inyectar ese control en el formulario :) (aunque me va a ser más propensos a probar el uso de la reflexión a la fuerza de la DoubleBuffered propiedad desde fuera, una vez más evitar la dependencia).

Es triste que un trivialmente simple cosa se comió gran parte de mi tiempo...

Nota:Hacer la respuesta, una respuesta para la pregunta puede ser marcado como respondida

Otros consejos

En el código siguiente se establece la propiedad mediante la reflexión, sin subclases como Benoit sugiere.

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

Para las personas que buscan la manera de hacerlo en VB.NET aquí está el código:

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

La adición a los artículos anteriores, para aplicaciones de Formularios Windows forms esto es lo que yo uso para DataGridView componentes para hacerlos rápidamente.El código de la clase DrawingControl está por debajo.

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

Llame DrawingControl.SetDoubleBuffered(control) después de InitializeComponent() en el constructor.

Llame DrawingControl.SuspendDrawing(control) antes de hacer grandes actualizaciones de los datos.

Llame DrawingControl.ResumeDrawing(control) después de hacer grandes actualizaciones de los datos.

Estos 2 últimos se hacen mejor con un try/finally bloque.(o mejor aún, la reescritura de la clase como IDisposable y llame a SuspendDrawing() en el constructor y ResumeDrawing() en 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();
    }
}

La respuesta a esto funcionó para mí también.Yo quisiera añadir un refinamiento que creo que debería ser práctica estándar para cualquier implementación de la solución.

La solución funciona bien excepto cuando la interfaz de usuario se ejecuta como una sesión de cliente en escritorio remoto, especialmente donde el ancho de banda disponible es baja.En tal caso, el rendimiento puede ser agravada por el uso de doble búfer.Por lo tanto, sugiero el siguiente como una respuesta más completa:

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

Para obtener más detalles, consulte Detección de conexión a escritorio remoto

He encontrado una solución para el problema.Ir a la ficha solución de problemas en las propiedades avanzadas de visualización y comprobar el control deslizante aceleración de hardware.Cuando llegué a mi nueva empresa de la PC de ELLA, fue a una graduación de la plena y no tuve ningún problema con cuadrículas.Una vez que he actualizado el controlador de tarjeta de vídeo y la puso a full, pintura de controles datagrid se hizo muy lento.Así que puedo restablecer de nuevo a donde estaba y el problema desapareció.

Esperamos que este truco funciona para usted también.

Sólo añadir lo que hemos hecho para solucionar este problema:Hemos actualizado a la última versión de los drivers de Nvidia resuelto el problema.No hay código fue reescrito.

La integridad, la tarjeta es una Nvidia Quadro NVS 290 con controladores de Marzo de 2008 (v.169).Actualizar a la última versión (v.182 de fecha de Febrero de 2009) mejoró significativamente la pintura de eventos para todos mis controles, especialmente para el control DataGridView.

Esta cuestión no se ha visto en ningún tarjetas ATI (donde se produce el desarrollo).

Mejor!:

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

Hemos experimentado un problema similar utilizando .NET 3.0 y DataGridView en un monitor de sistema.

Nuestra aplicación le mostrará la grilla con un fondo gris, lo que indica que las células no podía ser cambiado.Al seleccionar un botón "modificar configuración", el programa podría cambiar el color de fondo de las celdas en blanco para indicar al usuario que el texto de celda podría ser cambiado.Un botón "cancelar" se podría cambiar el color de fondo de las mencionadas células grises.

Como el color de fondo cambiado no sería un parpadeo, una breve impresión de que es un defecto de tamaño de la cuadrícula con el mismo número de filas y columnas.Este problema se produce sólo en el monitor principal (nunca en la secundaria) y que no se producen en un único monitor de sistema.

El doble búfer de control, utilizando el ejemplo anterior, solucionado nuestro problema.Hemos apreciado mucho su ayuda.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top