winforms标签闪烁

我有一个问题,Label控件非常闪烁。

下面是一些重现问题的代码。

怎么解决这个?

更新:前一种情况的解决方案(表单直接包含标签)是使form.DoubleBuffered = true。 但这不是一般的解决方案。 例如,对于SplitContainer中的标签,我该怎么办? 这是我的真实情况。

更新的代码:

DoubleBufferedLabel.cs:

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms; namespace FlickerLabelTest { public class DoubleBufferedLabel : Label { public DoubleBufferedLabel() { DoubleBuffered = true; } } } 

DoubleBufferedSplitContainer.cs:

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms; namespace FlickerLabelTest { public class DoubleBufferedSplitContainer : SplitContainer { public DoubleBufferedSplitContainer() { DoubleBuffered = true; } } } 

Form1.cs中:

 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace FlickerLabelTest { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void timer1_Tick(object sender, EventArgs e) { label1.Text += "0"; } } } 

Form1.Designer.cs:

 namespace FlickerLabelTest { partial class Form1 { ///  /// Required designer variable. ///  private System.ComponentModel.IContainer components = null; ///  /// Clean up any resources being used. ///  /// true if managed resources should be disposed; otherwise, false. protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #region Windows Form Designer generated code ///  /// Required method for Designer support - do not modify /// the contents of this method with the code editor. ///  private void InitializeComponent() { this.components = new System.ComponentModel.Container(); this.timer1 = new System.Windows.Forms.Timer(this.components); this.label1 = new FlickerLabelTest.DoubleBufferedLabel(); this.splitContainer1 = new DoubleBufferedSplitContainer(); this.splitContainer1.Panel2.SuspendLayout(); this.splitContainer1.SuspendLayout(); this.SuspendLayout(); // // timer1 // this.timer1.Enabled = true; this.timer1.Interval = 1; this.timer1.Tick += new System.EventHandler(this.timer1_Tick); // // label1 // this.label1.Dock = System.Windows.Forms.DockStyle.Fill; this.label1.Location = new System.Drawing.Point(0, 0); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(186, 262); this.label1.TabIndex = 0; this.label1.Text = "label1"; // // splitContainer1 // this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; this.splitContainer1.Location = new System.Drawing.Point(0, 0); this.splitContainer1.Name = "splitContainer1"; // // splitContainer1.Panel2 // this.splitContainer1.Panel2.Controls.Add(this.label1); this.splitContainer1.Size = new System.Drawing.Size(284, 262); this.splitContainer1.SplitterDistance = 94; this.splitContainer1.TabIndex = 1; // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(284, 262); this.Controls.Add(this.splitContainer1); this.DoubleBuffered = true; this.Name = "Form1"; this.Text = "Form1"; this.WindowState = System.Windows.Forms.FormWindowState.Maximized; this.splitContainer1.Panel2.ResumeLayout(false); this.splitContainer1.ResumeLayout(false); this.ResumeLayout(false); } #endregion private System.Windows.Forms.Timer timer1; private DoubleBufferedLabel label1; private DoubleBufferedSplitContainer splitContainer1; } } 

Program.cs中:

 using System; using System.Collections.Generic; using System.Linq; using System.Windows.Forms; namespace FlickerLabelTest { static class Program { ///  /// The main entry point for the application. ///  [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } } } 

问题在于对接。 如果将Label.Dock从“ Fill更改为“ None ,请手动设置标签的大小以填充分割面板,然后将其锚定在所有面上,它不会闪烁。

如果要查看闪烁的原因,当Dock仍设置为Fill ,覆盖DoubleBufferedLabel类中的OnResize ,启动应用程序,并在运行时在OnResize设置断点。 为Size添加一个手表,您会看到它在设计时和运行时尺寸之间翻转。

我尝试在您的示例中使用常规的SplitContainerLabel ,在表单DoubleBuffer设置为False ,如果我在Label上将Dock设置为None ,则它不会闪烁。

将其粘贴到您的表单代码中以帮助Dock布局计算:

  protected override void OnLoad(EventArgs e) { label1.Size = this.ClientSize; base.OnLoad(e); } 

不是真正的答案,但为什么你想要每毫秒更新你的标签? 如果你的意思是1秒,你必须将你的间隔设置为1000。

你可以通过给表单时间重绘自己并使用更大的间隔来解决这个问题。

更新:结果是,将DoubleBuffered设置为true可以解决问题。 感谢csharptest.net指出这一点和DxCK纠正我。

我想你正在寻找这个: http : //msdn.microsoft.com/en-us/library/3t7htc9c.aspx

例:

 class Form1 : Form { public Form1() { this.DoubleBuffered = true; } } 

停止将定时器设置为1ms。 没有认真的,你在这里看到的是,标签试图跟上它的变化,但没有这样做,因为它们经常发生。 可能的解决方案是:

  • 选择一种不经常更改标签的方法
  • 在表单上激活双缓冲

为什么不通过异步委托运行标签更新function? 或者使用System.Threading命名空间来获得不同的风格。

另外,正如我之前提到的那样,如果你将表单上的DoubleBuffer属性设置为true(虽然它不是银弹)会很有用。

在表单上激活双缓冲将解决问题。 但这实际上是一种昂贵的解决方案。 如果您只是将以下内容添加到表单中:

  SetStyle(ControlStyles.AllPaintingInWmPaint, true); 

闪烁也将结束。

Windows操作系统的默认行为首先让所有窗口绘制背景,然后让它们进行实际绘制。 这是从过去开始,当时绘画字母实际上耗费了相当多的时间。 此标志告诉它立即折叠背景油漆和常规油漆(对于同一窗口)。

真正的双缓冲可以保留用于您实际自己绘画的情况(当您重写OnPaint时)。