减少C#表单控件中Control.set_Text(string)函数的执行时间

3
希望能快速得到答复(似乎SO非常擅长)……
我在我的应用程序中使用VS2010进行了性能分析,结果发现我花费了约20%的时间在Control.set_Text(string)函数中,因为我在应用程序的许多地方更新标签。
窗口有一个计时器对象(Forms timer,而不是Threading timer),它具有一个timer1_Tick回调,在每个tick上更新一个标签(以产生类似秒表的效果),并且每秒更新15个标签。
除了增加更新间隔之外,是否有其他结构或功能可以减少在表单上更新文本所花费的时间?
2个回答

7
我自己也遇到了这个问题,最终创建了一个简单的标签控件。
.Net的标签控件非常复杂,因此速度比我们想象的要慢。
您可以创建一个继承自Control的类,在构造函数中调用SetStyle使其双缓冲和用户绘制,然后重写OnPaint方法调用e.Graphics.DrawString并绘制Text属性。 最后,覆盖Text或TextChanged并调用Invalidate。
只要您不需要AutoSize,这将比标准Label控件快得多。
这是我的实现:(目前正在生产中使用)
///<summary>A simple but extremely fast control.</summary>
///<remarks>Believe it or not, a regular label isn't fast enough, even double-buffered.</remarks>
class FastLabel : Control {
    public FastLabel() {
        SetStyle(ControlStyles.AllPaintingInWmPaint
               | ControlStyles.CacheText
               | ControlStyles.OptimizedDoubleBuffer
               | ControlStyles.ResizeRedraw
               | ControlStyles.UserPaint, true);
    }
    protected override void OnTextChanged(EventArgs e) { base.OnTextChanged(e); Invalidate(); }
    protected override void OnFontChanged(EventArgs e) { base.OnFontChanged(e); Invalidate(); }

    static readonly StringFormat format = new StringFormat {
        Alignment = StringAlignment.Center,
        LineAlignment = StringAlignment.Center
    };
    protected override void OnPaint(PaintEventArgs e) {
        e.Graphics.DrawString(Text, Font, SystemBrushes.ControlText, ClientRectangle, format);
    }
}

如果您不想居中,可以去掉或更改StringFormat


这非常接近我所需要的,但我注意到了一些问题 - 我的字体现在看起来很奇怪,所有标签都需要重新调整大小以适应该变化。此外,现在我花费了30%的时间在DrawString函数中,这似乎并没有加快我的表单响应速度。有什么想法吗? - awshepard
我不确定为什么会发生这种情况。字体具体看起来是什么样子? - SLaks
字母和字距看起来稍微宽了一些 - 在两种情况下都是 MS Sans Serif 8.25 pt,但 FastLabel 只是更宽。 - awshepard

3

好的,为标签分配文本属性大约需要0.6纳秒左右。昂贵的是副作用。您可能已经打开了标签的AutoSize属性。因此,它需要创建字体句柄,在临时设备上呈现文本,测量结果字符串,考虑由于TrueType提示而人为拉伸字母形状以使其与显示器上的像素重合的副作用,还要调整修改后的ABC度量以使ClearType工作。然后告诉本机Windows控件需要更改其窗口大小。这将为标签以及标签控件的父容器控件产生绘画事件。再次执行相同的例程,现在实际上绘制像素。当启用Aero时,这会更改内存设备上下文中的字节,需要将其复制到视频设备驱动程序中以更新视频内存,以便用户可以看到结果。

是的,这需要时间。

编写自己的代码而不是让Windows Forms代替您编写代码来加快速度。覆盖OnPaint事件,使用TextRender.DrawText绘制标签。这是一个快速的解决方案,速度可轻松提高50倍。但缺少设计师的点和单击便利性。


我尝试快速使用这种方法,但我猜我需要做的不仅仅是创建一个简单的“class MyFastLabel:Label”来覆盖OnPaint方法吧?只有那个函数和TextRenderer.DrawText()方法,任何MyFastLabel都不会显示出来。还应该包括什么? - awshepard
我认为继承标签除了双缓冲之外不会提供任何速度优势。 - SLaks
@slaks:你完全错过了重点。一个表单或面板可以绘制标签能够绘制的任何内容。 - Hans Passant
我是在参考他的评论。 - SLaks

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接