C# VS2019 Windows Form开启AutoScroll属性后滚动闪烁问题求助
问题成因
你遇到的滚动闪烁是WinForm场景下的常见问题,核心原因有两个:
- 窗体默认未开启针对滚动场景优化的双缓冲机制,滚动时窗体会先擦除背景再重绘所有可见控件,多次交替绘制就会产生闪烁感
- 你在循环中逐个将控件添加到窗体,每次添加都会触发布局重绘,额外增加了绘制开销,也会加剧滚动时的卡顿闪烁
修复方案
按下面的步骤修改代码即可解决问题:
- 给动态生成的
allShows窗体开启双缓冲,同时开启复合绘制优化 - 控件批量添加前挂起窗体布局,全部添加完成后再恢复布局,减少不必要的重绘
- 可选优化:如果你的数据量较大,建议优先用
FlowLayoutPanel或者自定义绘制的列表控件替代手动生成大量独立控件,性能会更好
修改后的完整代码
private void allShowsToolStripMenuItem_Click(object sender, EventArgs e) { try { // 从数据库加载所有节目数据 DataTable dt = accesse.LoadAllShows(); // 创建展示页面窗体 Form allShows = new Form(); // ========== 新增:开启窗体双缓冲优化 ========== typeof(Form).InvokeMember( "DoubleBuffered", System.Reflection.BindingFlags.SetProperty | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic, null, allShows, new object[] { true } ); allShows.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint, true); allShows.UpdateStyles(); // 初始化控件数组 PictureBox[] pic = new PictureBox[dt.Rows.Count]; Label[] showName = new Label[dt.Rows.Count], season = new Label[dt.Rows.Count], eps = new Label[dt.Rows.Count], typ = new Label[dt.Rows.Count]; TextBox[] txtShowName = new TextBox[dt.Rows.Count], txtSeason = new TextBox[dt.Rows.Count], txtEps = new TextBox[dt.Rows.Count], txtTyp = new TextBox[dt.Rows.Count]; // 窗体基础属性配置 allShows.BackColor = Color.White; allShows.Font = new Font("Calibri", 14f, FontStyle.Regular); allShows.ForeColor = Color.Black; allShows.Size = new Size(1050, 700); allShows.StartPosition = FormStartPosition.CenterScreen; allShows.AutoScroll = true; allShows.AutoScrollMargin = new Size(0, 18); // 布局计算变量 int y = 325; // 控件垂直间距 bool xTurn = false; // 左右列切换标识 int yTurnNum = 0; // 行号计数 // ========== 新增:添加控件前挂起布局 ========== allShows.SuspendLayout(); for (int i = 0; i < dt.Rows.Count; i++) { // 海报图控件配置 pic[i] = new PictureBox(); pic[i].BorderStyle = BorderStyle.FixedSingle; pic[i].Size = new Size(162, 288); pic[i].SizeMode = PictureBoxSizeMode.StretchImage; pic[i].Image = Image.FromFile(dt.Rows[i][4].ToString()); // 节目名称标签配置 showName[i] = new Label(); showName[i].Text = "节目名称: " + dt.Rows[i][0]; showName[i].AutoSize = true; // 季数标签配置 season[i] = new Label(); season[i].Text = "季数: " + dt.Rows[i][1]; season[i].AutoSize = true; // 集数标签配置 eps[i] = new Label(); eps[i].Text = "集数: " + dt.Rows[i][2]; eps[i].AutoSize = true; // 类型标签配置 typ[i] = new Label(); typ[i].Text = "类型: " + dt.Rows[i][3]; typ[i].AutoSize = true; if (xTurn) { // 右列控件位置计算 pic[i].Location = new Point(515, pic[i - 1].Location.Y); showName[i].Location = new Point(687, showName[i - 1].Location.Y); season[i].Location = new Point(687, season[i - 1].Location.Y); eps[i].Location = new Point(687, eps[i - 1].Location.Y); typ[i].Location = new Point(687, typ[i - 1].Location.Y); xTurn = false; } else { // 左列控件位置计算 pic[i].Location = new Point(15, 15 + (yTurnNum * y)); showName[i].Location = new Point(187, 20 + (yTurnNum * y)); season[i].Location = new Point(187, 55 + (yTurnNum * y)); eps[i].Location = new Point(187, 90 + (yTurnNum * y)); typ[i].Location = new Point(187, 125 + (yTurnNum * y)); yTurnNum += 1; xTurn = true; } // 把控件添加到窗体 allShows.Controls.Add(pic[i]); allShows.Controls.Add(showName[i]); allShows.Controls.Add(season[i]); allShows.Controls.Add(eps[i]); allShows.Controls.Add(typ[i]); } // ========== 新增:所有控件添加完成后恢复布局 ========== allShows.ResumeLayout(false); allShows.PerformLayout(); allShows.ShowDialog(); } catch (Exception ex) { tools.ShowErrorMessageBox(ex.Message, "错误"); } }
如果以上修改后还是有轻微闪烁,你可以自定义一个继承自Form的子类,在构造函数中提前设置好所有绘制优化参数,再用这个子类创建你的allShows窗体即可。
内容的提问来源于stack exchange,提问作者TheDarkAbyss
相关产品推荐
相关产品推荐

