VS2022中OnPaint事件无法更新窗体问题求助
窗体在VS2022中无法更新的问题排查与解决
这段代码在Visual Studio 2010里能正常运行,但到了Visual Studio 2022就没法更新窗体。我试过开启DoubleBuffer、修改User styles,都没解决问题。后来发现在OnPaint()里强制调用Paint()能生效,但这明显不对——Paint()本来就该由系统内部触发。
原问题代码:
namespace Kaledoscópio { public partial class frmMain : Form { private readonly Random randomColor = new Random(); public frmMain() { InitializeComponent(); tmrStep.Tick += TmrStep_Tick; tmrStep.Start(); } private void TmrStep_Tick(object? sender, EventArgs e) { this.Invalidate(); } private void frmMain_OnPaint(object sender, PaintEventArgs e) { base.OnPaint(e); Graphics g = e.Graphics; Color defaultColor = Color.FromArgb(randomColor.Next(255), randomColor.Next(255), randomColor.Next(255)); using (Pen defaultPen = new Pen(defaultColor, 2)) { int intHeight = this.ClientSize.Height; int intWidth = this.ClientSize.Width; int intMiddleHeight = intHeight / 2; int intMiddleWidth = intWidth / 2; Point posTopLeft = new Point(0, 0); Point posTopRight = new Point(intWidth, 0); Point posBottomLeft = new Point(0, intHeight); Point posBottomRight = new Point(intWidth, intHeight); Point posMiddle = new Point(intMiddleWidth, intMiddleHeight); Point posMiddleTop = new Point(intMiddleWidth, 0); Point posMiddleLeft = new Point(0, intMiddleHeight); Point posMiddleRight = new Point(intWidth, intMiddleHeight); Point posMiddleBottom = new Point(intMiddleWidth, intHeight); int defaultStep = randomColor.Next(3, 10); int b1; for (b1 = 0; b1 <= intMiddleWidth; b1 += defaultStep) { g.DrawLine(defaultPen, posTopLeft.X + b1, posTopLeft.Y, posMiddle.X - b1, posMiddle.Y); g.DrawLine(defaultPen, posTopRight.X - b1, posTopRight.Y, posMiddle.X + b1, posMiddle.Y); g.DrawLine(defaultPen, posMiddle.X - b1, posMiddle.Y, posBottomLeft.X + b1, posBottomLeft.Y); g.DrawLine(defaultPen, posMiddle.X + b1, posMiddle.Y, posBottomRight.X - b1, posBottomRight.Y); } int b2; for (b2 = 0; b2 <= intMiddleHeight; b2 += defaultStep) { g.DrawLine(defaultPen, posMiddleTop.X, posMiddleTop.Y + b2, posMiddleLeft.X, posMiddleLeft.Y - b2); g.DrawLine(defaultPen, posMiddleTop.X, posMiddleTop.Y + b2, posMiddleRight.X, posMiddleRight.Y - b2); g.DrawLine(defaultPen, posMiddleRight.X, posMiddleRight.Y + b2, posMiddleBottom.X, posMiddleBottom.Y - b2); g.DrawLine(defaultPen, posMiddleLeft.X, posMiddleLeft.Y + b2, posMiddleBottom.X, posMiddleBottom.Y - b2); } } } } }
问题分析与修正
核心问题出在这几点:
- 绘制事件绑定错误:你写的
frmMain_OnPaint是普通事件处理方法,但WinForms中自定义窗体绘制的正确方式是重写Form的OnPaint虚方法。高版本.NET(VS2022默认用.NET 6+)对事件绑定校验更严格,若这个方法未关联Paint事件,就不会触发绘制。 - 双缓冲设置不完整:仅开启
DoubleBuffered=true可能不够,需同时设置多个ControlStyles并更新样式,才能确保双缓冲生效。 - 强制调用Paint()是错误操作:这会引发递归调用,既影响性能还可能导致异常,绝对不能这么做。
修正后的代码
namespace Kaledoscópio { public partial class frmMain : Form { private readonly Random randomColor = new Random(); public frmMain() { InitializeComponent(); // 完整开启双缓冲 this.DoubleBuffered = true; this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true); this.UpdateStyles(); tmrStep.Tick += TmrStep_Tick; tmrStep.Start(); } private void TmrStep_Tick(object? sender, EventArgs e) { this.Invalidate(); } // 重写Form的OnPaint虚方法,替代原来的事件处理方法 protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); Graphics g = e.Graphics; Color defaultColor = Color.FromArgb(randomColor.Next(255), randomColor.Next(255), randomColor.Next(255)); using (Pen defaultPen = new Pen(defaultColor, 2)) { int intHeight = this.ClientSize.Height; int intWidth = this.ClientSize.Width; int intMiddleHeight = intHeight / 2; int intMiddleWidth = intWidth / 2; Point posTopLeft = new Point(0, 0); Point posTopRight = new Point(intWidth, 0); Point posBottomLeft = new Point(0, intHeight); Point posBottomRight = new Point(intWidth, intHeight); Point posMiddle = new Point(intMiddleWidth, intMiddleHeight); Point posMiddleTop = new Point(intMiddleWidth, 0); Point posMiddleLeft = new Point(0, intMiddleHeight); Point posMiddleRight = new Point(intWidth, intMiddleHeight); Point posMiddleBottom = new Point(intMiddleWidth, intHeight); int defaultStep = randomColor.Next(3, 10); int b1; for (b1 = 0; b1 <= intMiddleWidth; b1 += defaultStep) { g.DrawLine(defaultPen, posTopLeft.X + b1, posTopLeft.Y, posMiddle.X - b1, posMiddle.Y); g.DrawLine(defaultPen, posTopRight.X - b1, posTopRight.Y, posMiddle.X + b1, posMiddle.Y); g.DrawLine(defaultPen, posMiddle.X - b1, posMiddle.Y, posBottomLeft.X + b1, posBottomLeft.Y); g.DrawLine(defaultPen, posMiddle.X + b1, posMiddle.Y, posBottomRight.X - b1, posBottomRight.Y); } int b2; for (b2 = 0; b2 <= intMiddleHeight; b2 += defaultStep) { g.DrawLine(defaultPen, posMiddleTop.X, posMiddleTop.Y + b2, posMiddleLeft.X, posMiddleLeft.Y - b2); g.DrawLine(defaultPen, posMiddleTop.X, posMiddleTop.Y + b2, posMiddleRight.X, posMiddleRight.Y - b2); g.DrawLine(defaultPen, posMiddleRight.X, posMiddleRight.Y + b2, posMiddleBottom.X, posMiddleBottom.Y - b2); g.DrawLine(defaultPen, posMiddleLeft.X, posMiddleLeft.Y + b2, posMiddleBottom.X, posMiddleBottom.Y - b2); } } } } }
额外注意事项
- 确保定时器
tmrStep的Interval属性设置合理(比如50-100ms),避免绘制过于频繁导致界面卡顿。 - 若修改后仍有问题,可检查窗体的
AutoScaleMode设置,高版本.NET的自动缩放逻辑和旧版本不同,可能影响绘制区域。
内容的提问来源于stack exchange,提问作者Lorenzo Berendsen
相关产品推荐
相关产品推荐

