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