[英]Rendering controls on glass: Solution found, needs double-buffering/perfecting
我(終於。)找到了一種在玻璃上呈現 Windows.Forms 控件的方法,該控件似乎沒有任何重大缺陷,也沒有任何大的實施時間。 它的靈感來自 Coded 的 這篇文章,它基本上解釋了如何在本地覆蓋控件的繪制以在它們之上繪制。
我使用這種方法將控件渲染到 bitmap 並在 NativeWindow 的繪畫區域上使用 GDI+ 和適當的 alpha 通道將其重新繪制。 實現很簡單,但可以完善可用性,但這不是這個問題的重點。 然而,結果非常令人滿意:
但是,需要修復兩個區域才能使其真正可用。
SetStyles(this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true)
將基本控件設置為雙緩沖不起作用,但我懷疑我們可以通過一些試驗和錯誤使其工作。某些控件不起作用。 我已經能夠完成以下工作:
但我不能讓這些工作,雖然我不明白為什么不。 我有根據的猜測是,我引用整個控件的實際 NativeWindow 句柄,而我需要引用它的“輸入”(文本)部分,可能是一個孩子。 歡迎 WinAPI 專家就如何獲得輸入 window 句柄提供任何幫助。
但是修復雙緩沖將是可用性的主要焦點。
這是一個示例用法:
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)
}
}
我之前有閃爍的問題(表單上有很多控件,用戶控件)。 幾乎什么都試過了。 這對我有用:
您是否嘗試將其放入您的表格 class 中?
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);
它僅在啟用 aero 時有效,否則會使閃爍更加嚴重。
你也可以添加這個
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x02000000; // WS_EX_COMPOSITED
return cp;
}
}
到您的用戶控件 class。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.