You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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);
                }
            }
        }
    }
}

问题分析与修正

核心问题出在这几点:

  1. 绘制事件绑定错误:你写的frmMain_OnPaint是普通事件处理方法,但WinForms中自定义窗体绘制的正确方式是重写Form的OnPaint虚方法。高版本.NET(VS2022默认用.NET 6+)对事件绑定校验更严格,若这个方法未关联Paint事件,就不会触发绘制。
  2. 双缓冲设置不完整:仅开启DoubleBuffered=true可能不够,需同时设置多个ControlStyles并更新样式,才能确保双缓冲生效。
  3. 强制调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 09:27:41