2012-02-03 9 views
6

Tengo algunos componentes personalizados (winforms) que se dibujan en la pantalla usando GDI +.¿Qué podría hacer que Double Buffering matara mi aplicación?

para evitar el parpadeo de repintado, decidí permitir que el doble buffer, por lo que añade una línea a mi constructor:

public ColourWheel() 
{ 
    InitializeComponent(); 
    this.DoubleBuffered = true; 
} 

que funciona muy bien en este componente (rueda de color). Cuando agrego la misma línea para el constructor de cualquiera de mis otros dos componentes (de estructura similar), consigo un par de extraños síntomas:

  1. Cuando trato de ejecutar un formulario con el componente de, consigo un Excepción de argumento en Application.Run(new Form());.
  2. Si cambio al modo de diseño, aparece un error sobre el componente que tiene una excepción no controlada para hacer con un parámetro.

No parece importar si uso doble buffering en uno o en todos ellos, todavía funciona en ColourWheel, pero no en los demás.

Para el registro, también he intentado unas pocas otras técnicas doublebuffering.

¿Qué podría estar causando que el doble buffer funcione en un componente, pero no en otros?


EDIT: En detalle excepción del síntoma en tiempo de ejecución:

System.ArgumentException fue no controlada Mensaje = El parámetro no es válido . Fuente = System.Drawing StackTrace: en System.Drawing.Graphics.GetHdc() en System.Drawing.BufferedGraphics.RenderInternal (HandleRef refTargetDC, tampón BufferedGraphics) en System.Drawing.BufferedGraphics.Render() en System.Windows .Forms.Control.WmPaint (Mensaje & m) en System.Windows.Forms.Control.WndProc (Mensaje & m) en System.Windows.Forms.ScrollableControl.WndProc (Mensaje & m) en System.Windows.Forms .UserControl.WndProc (mensaje & m) en System.Windows.Forms.Control.ControlNativeWindow.OnMessage (mensaje & m) en System.Windows.Forms.Co ntrol.ControlNativeWindow.WndProc (Mensaje & m) en System.Windows.Forms.NativeWindow.DebuggableCallback (IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam) en System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW (MSG & msg) en System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop (IntPtr dwComponentID, Int32 razón, Int32 pvLoopData) en System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner (Int32 razón, contexto ApplicationContext) en System.Windows.Forms.Application.ThreadContext.RunMessageLoop (Int32 reason, ApplicationContext context) en S ystem.Windows.Forms.Application.Run (Form mainForm) en TestForm.Program.Main() en D: \ Documents and Settings \ Tom Wright \ Mis documentos \ Visual Studio 2010 \ Projects \ ColourPicker \ TestForm \ Program.cs: línea 18 en System.AppDomain._nExecuteAssembly (ensamblado RuntimeAssembly, String [] args) en System.AppDomain.ExecuteAssembly (String assemblyFile, assemblySecurity Evidencia, String [] args) en Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() en System.Threading.ThreadHelper.ThreadStart_Context (estado Object) en System.Threading .ExecutionContext.Run (ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx) en System.Threading.ExecutionContext.Run (ExecutionContext executionContext, ContextCallback callback, estado Objeto) en System.Threading.ThreadHelper.ThreadStart() InnerException:


EDIT 2: problemas El manejador OnPaint de uno (el más complicado) de los dos componentes que están causando:

private void ValueSlider_Paint(object sender, PaintEventArgs e) 
{ 
     using (Graphics g = e.Graphics) 
     { 
      g.DrawImage(this.gradientImage, new Rectangle(0, 0, paintArea.Width, paintArea.Height)); 
      if (this.showmarker) 
      { 
       ColourHandler.HSV alt = ColourHandler.RGBtoHSV(new ColourHandler.RGB(this.SelectedColour.R, this.SelectedColour.G, this.SelectedColour.B)); 
       alt.Saturation = 0; 
       alt.value = 255 - alt.value; 
       using (Pen pen = new Pen(ColourHandler.HSVtoColour(alt))) 
       { 
        pen.Width = (float)MARKERWIDTH; 
        g.DrawRectangle(pen, 0 - pen.Width, this.brightnessPoint.Y - MARKERWIDTH, this.paintArea.Width + (pen.Width * 2), MARKERWIDTH * 2); 
       } 
      } 
     } 
} 
+0

Comparta la excepción. – roken

+1

@roken Todo tuyo mi amigo. –

+0

¿Está anulando OnPaint() en los controles ofensores? Si es así, ¿cómo se ve eso? – roken

Respuesta

8

Se supone que no debe deshacerse del objeto Graphics que se le ha prestado durante el evento Paint, y eso es lo que su bloque using hace indebidamente.

El síntoma es que la próxima vez que el Paint desencadena el evento, se obtiene el mismo Graphics objeto de nuevo, pero ya no está obligado a una en memoria HDC, causando Graphics.GetHdc() que fallan como se ve en el seguimiento de la pila.

  1. Es posible que sobrevive a un solo evento Paint (y esto es muy probable que en el caso de doble búfer, aunque también es posible con un solo búfer si se establece el estilo CS_OWNDC ventana).

  2. Puede haber más de un controlador para el evento Paint.

Así, los controladores de eventos no deben llamar Dispose en los Graphics objetos o permitir un bloque using para hacerlo. En su lugar, el .NET Framework limpia los recursos según corresponda después de que se complete el manejo de eventos Paint.

+1

Funcionó durante más de un año y luego, cuando moví la clase de control de usuario a su propio archivo, comencé a arrojar el error OP aquí obtenido. Lo que sugirió funcionó: ¡C# puede ser realmente extraño algunas veces! –

1

Debe probar esto en otra máquina para ver si es solo su computadora o no. En su mayor parte, esto no debería ocurrir como resultado del doble almacenamiento en búfer, pero verifique si está eliminando elementos que no deberían estar en el evento Paint o haciendo algo en el código que tendría problemas si se hace dos veces.

+2

No creo que deba deshacerse del objeto 'Graphics' que se le entregó durante el evento' Paint'. –

+0

@ben tiene razón. No hagas 'usar' en 'g', ya que esto eliminará el objeto Graphics cuando salgas de ese alcance, pero no eres el 'propietario' de ese objeto. –

+0

Gracias chicos. Estaba haciendo 'using (Graphics g = e.Graphics) {}'. Eliminar esta era la clave. –

Cuestiones relacionadas