在 WinForms GDI+ 繪圖中,畫面閃爍主要源自兩類場景:
Paint 事件。Paint 極高頻率觸發。// .NET 2.0+ 必須使用 OptimizedDoubleBuffer
this.SetStyle(
ControlStyles.OptimizedDoubleBuffer | // 雙緩衝
ControlStyles.ResizeRedraw | // 大小改變重繪
ControlStyles.AllPaintingInWmPaint, // 禁止擦除背景,減少閃爍
true);
注意:.NET 1.1 使用ControlStyles.DoubleBuffer,2.0 後改為OptimizedDoubleBuffer,混用會報「參數無效」。
核心邏輯:在記憶體建立離屏畫布 → 全部圖元繪製到畫布 → 一次性將畫布貼到螢幕。提供兩種實作方式:
protected override void OnPaint(PaintEventArgs e) {
Rectangle rect = e.ClipRectangle;
// 1. 建立與控件同尺寸的 Bitmap
using (Bitmap buffer = new Bitmap(this.Width, this.Height)) {
using (Graphics g = Graphics.FromImage(buffer)) {
g.Clear(this.BackColor);
g.SmoothingMode = SmoothingMode.HighQuality;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
// 2. 遍歷圖元,繪製到離屏 Graphics
foreach (IShape obj in doc.drawObjectList) {
if (rect.IntersectsWith(obj.Rect)) {
obj.Draw(g);
// 選取態熱點繪製
if (obj.TrackerState == TrackerState.Selected &&
this.CurrentOperator == Operator.Transform) {
obj.DrawTracker(g);
}
}
}
}
// 3. 一次性貼圖到螢幕
using (Graphics screen = e.Graphics) {
screen.DrawImage(buffer, 0, 0);
}
}
}
protected override void OnPaint(PaintEventArgs e) {
Rectangle rect = e.ClipRectangle;
// 1. 從管理器配置緩衝區(自動處理尺寸、裝置相容)
BufferedGraphicsContext ctx = BufferedGraphicsManager.Current;
using (BufferedGraphics buffer = ctx.Allocate(e.Graphics, e.ClipRectangle)) {
Graphics g = buffer.Graphics;
g.SmoothingMode = SmoothingMode.HighQuality;
g.PixelOffsetMode = PixelOffsetMode.HighSpeed;
g.Clear(this.BackColor);
// 2. 同樣遍歷繪製
foreach (IShape obj in doc.drawObjectList) {
if (rect.IntersectsWith(obj.Rect)) {
obj.Draw(g);
if (obj.TrackerState == TrackerState.Selected &&
this.CurrentOperator == Operator.Transform) {
obj.DrawTracker(g);
}
}
}
// 3. 渲染到螢幕
buffer.Render(e.Graphics);
} // using 確保 Dispose,釋放非托管資源
}
| 維度 | 手動 Bitmap | BufferedGraphics |
|---|---|---|
| 實作複雜度 | 略高(需自行管理 Bitmap 生命週期) | 低(框架封裝佳) |
| 記憶體佔用 | 較大(全尺寸 Bitmap) | 較小(可僅配置裁剪區域) |
| 效能 | 良好 | 更優(內部優化) |
| 資源洩漏風險 | 較高(易忘 Dispose) | 低(using 自動釋放) |
| 建議場景 | 需精細控制畫布像素操作 | 通用繪圖、高頻重繪、長時間運行程式 |
e.ClipRectangle 範圍內的圖元(代碼中已示範 rect.IntersectsWith)。DrawImage。SmoothingMode.HighQuality + PixelOffsetMode.HighQuality 顯著提升視覺品質。雙緩衝 = 控件樣式啟用 + 離屏繪製一次性呈現。掌握 BufferedGraphics 現代寫法,配合裁剪區域與資源釋放最佳實踐,即可徹底解決 GDI+ 繪圖閃爍問題,打造絲滑流暢的視覺體驗。