玻璃上的渲染控件:找到解决方案,需要翻一番
我(终于!)找到了一种在Windows上呈现Windows.Forms控件的方式,它似乎没有任何主要缺点,也没有任何大的实施时间。 它的灵感来自Coded的这篇文章,它基本上解释了如何在本地重写控件的绘画来绘制它们。
我使用该方法将控件渲染为位图,并使用GDI +和适当的Alpha通道在NativeWindow的绘制区域上绘制回来。 这个实现很简单,但可以通过可用性来完善,但这不是这个问题的关键。 但结果令人非常满意:
但是,有两个方面需要修复才能真正使用。
SetStyles(this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true)
进行双缓冲SetStyles(this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true)
不起作用,但我怀疑我们可以通过一些试验和错误使它工作。 一些控件不起作用 。 我已经能够做出以下工作:
但我不能让这些工作,但我不明白为什么不。 我的教育猜测是,我引用整个控件的实际NativeWindow句柄,而我需要引用它的“输入”(文本)部分,可能是一个孩子。 欢迎任何来自WinAPI专家的关于如何获得输入窗口句柄的帮助。
但修复双缓冲将是可用性的主要焦点 。
以下是一个示例用法:
new GlassControlRenderer(textBox1);
代码如下:
public class GlassControlRenderer : NativeWindow
{
private Control Control;
private Bitmap Bitmap;
private Graphics ControlGraphics;
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case 0xF: // WM_PAINT
case 0x85: // WM_NCPAINT
case 0x100: // WM_KEYDOWN
case 0x200: // WM_MOUSEMOVE
case 0x201: // WM_LBUTTONDOWN
this.Control.Invalidate();
base.WndProc(ref m);
this.CustomPaint();
break;
default:
base.WndProc(ref m);
break;
}
}
public GlassControlRenderer(Control control)
{
this.Control = control;
this.Bitmap = new Bitmap(this.Control.Width, this.Control.Height);
this.ControlGraphics = Graphics.FromHwnd(this.Control.Handle);
this.AssignHandle(this.Control.Handle);
}
public void CustomPaint()
{
this.Control.DrawToBitmap(this.Bitmap, new Rectangle(0, 0, this.Control.Width, this.Control.Height));
this.ControlGraphics.DrawImageUnscaled(this.Bitmap, -1, -1); // -1, -1 for content controls (e.g. TextBox, ListBox)
}
}
我真的很高兴能够解决这个问题,并且一劳永逸地为所有的.NET控件提供真正的渲染方式,无需WPF。
编辑:双缓冲/防闪烁的可能路径:
this.Control.Invalidate()
删除闪烁,但打破了文本框中的输入。 我试过WM_SETREDRAW方法和SuspendLayout方法,但没有运气:
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, Int32 wMsg, bool wParam, Int32 lParam);
private const int WM_SETREDRAW = 11;
public static void SuspendDrawing(Control parent)
{
SendMessage(parent.Handle, WM_SETREDRAW, false, 0);
}
public static void ResumeDrawing(Control parent)
{
SendMessage(parent.Handle, WM_SETREDRAW, true, 0);
parent.Refresh();
}
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case 0xF: // WM_PAINT
case 0x85: // WM_NCPAINT
case 0x100: // WM_KEYDOWN
case 0x200: // WM_MOUSEMOVE
case 0x201: // WM_LBUTTONDOWN
//this.Control.Parent.SuspendLayout();
//GlassControlRenderer.SuspendDrawing(this.Control);
//this.Control.Invalidate();
base.WndProc(ref m);
this.CustomPaint();
//GlassControlRenderer.ResumeDrawing(this.Control);
//this.Control.Parent.ResumeLayout();
break;
default:
base.WndProc(ref m);
break;
}
}
这是一个闪烁少得多的版本,但仍然不完美。
public class GlassControlRenderer : NativeWindow
{
private Control Control;
private Bitmap Bitmap;
private Graphics ControlGraphics;
private object Lock = new object();
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case 0x14: // WM_ERASEBKGND
this.CustomPaint();
break;
case 0x0F: // WM_PAINT
case 0x85: // WM_NCPAINT
case 0x100: // WM_KEYDOWN
case 0x101: // WM_KEYUP
case 0x102: // WM_CHAR
case 0x200: // WM_MOUSEMOVE
case 0x2A1: // WM_MOUSEHOVER
case 0x201: // WM_LBUTTONDOWN
case 0x202: // WM_LBUTTONUP
case 0x285: // WM_IME_SELECT
case 0x300: // WM_CUT
case 0x301: // WM_COPY
case 0x302: // WM_PASTE
case 0x303: // WM_CLEAR
case 0x304: // WM_UNDO
base.WndProc(ref m);
this.CustomPaint();
break;
default:
base.WndProc(ref m);
break;
}
}
private Point Offset { get; set; }
public GlassControlRenderer(Control control, int xOffset, int yOffset)
{
this.Offset = new Point(xOffset, yOffset);
this.Control = control;
this.Bitmap = new Bitmap(this.Control.Width, this.Control.Height);
this.ControlGraphics = Graphics.FromHwnd(this.Control.Handle);
this.AssignHandle(this.Control.Handle);
}
public void CustomPaint()
{
this.Control.DrawToBitmap(this.Bitmap, new Rectangle(0, 0, this.Control.Width, this.Control.Height));
this.ControlGraphics.DrawImageUnscaled(this.Bitmap, this.Offset); // -1, -1 for content controls (e.g. TextBox, ListBox)
}
}
之前我有一个闪烁的问题(表单上的很多控件,用户控件)。 尝试几乎所有的东西。 这对我来说很有用:
你有没有尝试把这个放在你的表单类中?
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x02000000; // WS_EX_COMPOSITED
cp.ExStyle |= 0x00080000; // WS_EX_LAYERED
return cp;
}
}
而在你的构造函数中你必须启用双缓冲,否则它将无法工作:
this.DoubleBuffered = true;
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
它只在航空启用时才起作用,否则会使闪烁变得更糟。
你也可以添加这个
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x02000000; // WS_EX_COMPOSITED
return cp;
}
}
到你的UserControls类。
链接地址: http://www.djcxy.com/p/50305.html上一篇: Rendering controls on glass: Solution found, needs double
下一篇: Why does DrawImageUnscaled cause flickering when used from WM