2012-02-03 3 views
6

У меня есть несколько пользовательских (winforms) компонентов, которые рисуют на экране с помощью GDI +.Что может заставить Double Buffering убить мое приложение?

Чтобы предотвратить мерцание перекрашивать, я решил включить двойную буферизацию, так что я добавил строку в мой конструктор:

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

Который работает отлично на этом компоненте (ColourWheel). Когда я добавляю ту же строку в конструктор либо из моих двух других (аналогично структурированных) компонентов, я получаю несколько странных симптомов:

  1. Когда я пытаюсь запустить форму с компонентом на, я получаю Исключение аргумента: Application.Run(new Form());.
  2. Если я переключусь в режим разработки, я получаю сообщение об ошибке, когда компонент, имеющий необработанное исключение, может использовать параметр.

Не похоже, что я поворачиваю двойную буферизацию на одну или все из них, она все еще работает на ColourWheel, но не на других.

Для справки, я также пробовал несколько других методов doublebuffering.

Что может быть причиной двойной буферизации для работы с одним компонентом, но не с другими?


EDIT: Вот деталь исключения из времени выполнения симптома:

System.ArgumentException был необработанное Сообщение = Параметр не действительными. Источник = System.Drawing StackTrace: на System.Drawing.Graphics.GetHdc() в System.Drawing.BufferedGraphics.RenderInternal (HandleRef refTargetDC, BufferedGraphics буфер) на System.Drawing.BufferedGraphics.Render() в System.Windows .Forms.Control.WmPaint (Сообщение & м) на System.Windows.Forms.Control.WndProc (сообщение & м) на System.Windows.Forms.ScrollableControl.WndProc (Сообщение & м) на System.Windows.Forms .UserControl.WndProc (Message & m) at System.Windows.Forms.Control.ControlNativeWindow.OnMessage (Message & m) at System.Windows.Forms.Co ntrol.ControlNativeWindow.WndProc (сообщение & м) на System.Windows.Forms.NativeWindow.DebuggableCallback (IntPtr HWND, Int32 MSG, IntPtr WPARAM, IntPtr LPARAM) на System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW (МСГ & MSG) на System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop (IntPtr dwComponentID, Int32, Int32 причине pvLoopData) в System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner (Int32 причина, контекст ApplicationContext) в System.Windows.Forms.Application.ThreadContext.RunMessageLoop (Int32 причина, контекст ApplicationContext) на S ystem.Windows.Forms.Application.Run (Form mainForm) в TestForm.Program.Main() в D: \ Documents and Settings \ Tom Wright \ Мои документы \ Visual Studio 2010 \ Projects \ ColourPicker \ TestForm \ Program.cs: строка 18 в System.AppDomain._nExecuteAssembly (сборка RuntimeAssembly, String [] args) в System.AppDomain.ExecuteAssembly (String, Evidence assemblyFile assemblySecurity, String [] арг) в Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() в System.Threading.ThreadHelper.ThreadStart_Context (состояние объекта) в System.Threading .ExecutionContext.Run (ExecutionContext executeContext, ContextCallback callback, состояние объекта, Boolean ignoreSyncCtx) в System.Threading.ExecutionContext.Run (ИсполнениеКонтекстовое исполнениеКонтекст, Обратный вызов ContextCallback, Состояние объекта) на System.Threading.ThreadHelper.ThreadStart() InnerException:


EDIT 2: обработчик OnPaint от одного (более сложный) из двух компонентов, которые вызывают проблемы:

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

Пожалуйста, поделитесь этим случаем. – roken

+1

@roken Все ваши друзья. –

+0

Вы переопределяете OnPaint() в нарушении правил? Если да, то как это выглядит? – roken

ответ

8

Вы не должны размещать объект Graphics, который был предоставлен вам во время события Paint, и это ваш код using неправильно.

Симптомом является то, что в следующий раз Paint событие срабатывает, вы получите тот же Graphics объекта обратно, но он больше не обязан в оперативной памяти HDC, вызывая Graphics.GetHdc() потерпеть неудачу, как показано в вашей трассировке стеки.

  1. Вполне возможно, что она переживет один Paint события (и это весьма вероятно, в случае с двойной буферизацией, хотя это также возможно с одним буферизацией, если стиль CS_OWNDC окна установлен).

  2. Для события Paint может быть более одного обработчика.

Таким образом, обработчики событий не должны вызывать Dispose на Graphics объектов или позволить using блок сделать это. Вместо этого среда .NET очищает ресурсы по мере необходимости после завершения обработки событий Paint.

+1

Он работал более года, а затем, когда я переместил класс управления пользователя в свой собственный файл, начал бросать ошибку OP здесь. То, что вы предложили, - C# иногда может быть странным! –

1

Вы должны проверить это на другой машине, чтобы убедиться, что это только ваш компьютер или нет. По большей части это не должно происходить в результате двойной буферизации, но проверьте, не удаляете ли вы какие-либо элементы, которые не должны находиться в событии Paint, или что-либо делать в коде, который будет иметь проблемы, если это делается дважды.

+2

Я не думаю, что вы должны распоряжаться объектом «Graphics», данным вам во время события «Paint». –

+0

@ben является правильным. Не выполняйте «использование» на «g», так как это приведет к удалению объекта Graphics при выходе из этой области, но вы не являетесь «владельцем» этого объекта. –

+0

Спасибо, ребята. Я выполнял 'using (Graphics g = e.Graphics) {}'. Удаление этого ключа было ключевым. –

Смежные вопросы