Why does DrawImageUnscaled cause flickering when used from WM
I'm currently building a control derived from System.Windows.Forms.ContainerControl
that has a border area I need to paint myself. Since there's no OnPaintNonClientArea
to override, I built it myself like this (handling of other messages like WM_NCCALCSIZE
, WM_NCHITTEST
etc. removed for brevity):
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);
}
Within OnPaintNonClientArea
, I did:
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);
}
Leaving OnPaintNonClientArea
untouched, this removes the flicker:
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);
}
So, why does DrawImageUnscaled
cause this flickering? It seems to erase the area it works on with a white brush before drawing the buffer. I didn't find anything in the docs that clarified this issue. It wouldn't matter too much if it were just a small border around the control, but there will be text displayed within the NC area, so the area is clearly visible and therefore the flickering is really visible and annoying.
Related questions: Am I doing the native GDI stuff right, or are there potential problems I don't see right now? Also, when creating the ncBitmap
, I'm using the control width and height, but GDI+ is resolution-independant, can there be any problems there?
To avoid flickering in UserControl's, I've had better luck with the BufferedGraphics class.
MSDN
Is that an option?
链接地址: http://www.djcxy.com/p/50304.html