Почему DrawImageUnscaled вызывает мерцание при использовании из WM_NCPAINT? - PullRequest
5 голосов
/ 06 июня 2011

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

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 + не зависит от разрешения, могут ли быть какие-то проблемы там?

1 Ответ

2 голосов
/ 16 июня 2011

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

* MSDN 1004 *

Это вариант?

...