2011-06-06 4 views
5

В настоящее время я строю элемент управления, полученный из System.Windows.Forms.ContainerControl, который имеет граничную область, которую мне нужно нарисовать. Поскольку нет никакого OnPaintNonClientArea переопределить, я построил его сам, как это (обращение с другими сообщениями, как WM_NCCALCSIZE, WM_NCHITTEST и т.д. удалены для краткости):Почему DrawImageUnscaled вызывает мерцание при использовании с WM_NCPAINT?

protected override void WndProc(ref Message m) 
{ 
    switch (m.Msg) 
    { 
    case WM_NCPAINT: 
     IntPtr hDC = NativeApi.Methods.GetWindowDC(m.HWnd); 
     if (hDC != IntPtr.Zero) 
     { 
     using (Graphics canvas = Graphics.FromHdc(hDC)) 
     { 
      if (Width > 0 && Height > 0) 
      using (PaintEventArgs e = new PaintEventArgs(canvas, new Rectangle(0, 0, Width, Height))) 
      { 
       OnPaintNonClientArea(e); 
      } 
     } 
     NativeApi.Methods.ReleaseDC(m.HWnd, hDC); 
     } 
     m.Result = IntPtr.Zero; 
     break; 
    } 
    base.WndProc(ref m); 
} 

В течение OnPaintNonClientArea, я сделал:

private void OnPaintNonClientArea(PaintEventArgs e) 
{ 
    if (_ncBuffer == null) 
    { 
    _ncBuffer = new Bitmap(Width, Height); 
    } 

    using (Graphics g = Graphics.FromImage(_ncBuffer)) 
    { 
    // painting occurs here ... 
    } 
    // this causes flickering 
    e.Graphics.DrawImageUnscaled(_ncBuffer, 0, 0, Width, Height); 
} 

Оставляя OnPaintNonClientArea нетронутым, это устраняет мерцание:

protected override void WndProc(ref Message m) 
{ 
    switch (m.Msg) 
    { 
    case WM_NCPAINT: 
     using(Bitmap ncBitmap = new Bitmap(Width, Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)) 
     { 
     using(Graphics ncGraphics = Graphics.FromImage(ncBitmap)) 
     { 
      using (PaintEventArgs e = new PaintEventArgs(ncGraphics, new Rectangle(0, 0, Width, Height))) 
      { 
      OnPaintNonClientArea(e); 
      IntPtr hDCWin = NativeApi.Methods.GetWindowDC(m.HWnd); 
      IntPtr hDCImg = ncGraphics.GetHdc(); 
      IntPtr hBmp = ncBitmap.GetHbitmap(); 
      IntPtr hBmpOld = NativeApi.Methods.SelectObject(hDCImg, hBmp); 
      Padding p = GetNonClientArea(); 
      NativeApi.Methods.ExcludeClipRect(hDCWin, p.Left, p.Top,Width- p.Right, Height-p.Bottom); 
      NativeApi.Methods.BitBlt(hDCWin, 0, 0, Width, Height, hDCImg, 0, 0,NativeApi.TernaryRasterOperations.SRCCOPY); 
      NativeApi.Methods.SelectObject(hDCImg, hBmpOld); 
      NativeApi.Methods.DeleteObject(hBmp); 
      ncGraphics.ReleaseHdc(hDCImg); 
      NativeApi.Methods.ReleaseDC(m.HWnd, hDCWin); 
      } 
     } 
     } 
     m.Result = IntPtr.Zero; 
     break; 
    } 
    base.WndProc(ref m); 
} 

Итак, почему же DrawImageUnscaled вызывают это мерцание? Кажется, он стирает область, в которой он работает, с белой кистью, прежде чем рисовать буфер. Я ничего не нашел в документах, которые прояснили эту проблему. Это не имело бы большого значения, если бы это была небольшая граница вокруг элемента управления, но в области ЧПУ будет отображаться текст, поэтому область хорошо видна, и поэтому мерцание действительно заметно и раздражает.

Связанные вопросы: Я делаю собственный материал GDI правильно, или есть потенциальные проблемы, которые я не вижу прямо сейчас? Кроме того, при создании ncBitmap я использую ширину и высоту управления, но GDI + является независимым от разрешения, могут ли быть какие-либо проблемы там?

+0

Вы пытались использовать двойную буферизацию в форме? Двойная буферизация должна иметь дело с такими графическими проблемами. Кроме того, существуют ли эквиваленты SuspendLayout и PerformLayout, которые вы могли бы использовать, чтобы остановить обновление элемента управления до того, как вы загрузили графический объект? –

+0

Спасибо за это. Я довольно долго искал этот материал и пробовал всевозможные вещи, в какой-то момент я сделал двойную бубную форму, которая не имела никакого значения. Я не думаю, что это применимо здесь, так как я фактически делаю двойное буферизацию уже - я рисую все вещи, используя объект «Graphics», а затем используя «DrawImageUnscaled». Я пытаюсь нарисовать буфер на объект Graphics, созданный ' Graphics.FromHdc (HDC) '. Это DrawImageUnscaled, который сначала стирает область, которую нужно нарисовать, используя белую кисть, а затем рисует содержимое объекта Graphics. Не уверен, что это можно исправить. – takrl

ответ

2

Чтобы избежать мерцания в UserControl, мне повезло с классом BufferedGraphics.

MSDN

Это вариант?

+1

+1 для подхода, о котором я не знал. Но для рисования неклиентской области это вызвало столько же мерцания, как и первый подход, который я пробовал. – takrl

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