Hoping for a quick answer (which SO seems to be pretty good for)...
I just ran a performance analysis with VS2010 on my app, and it turns out that I'm spending about 20% of my time in the Control.set_Text(string) function, as I'm updating labels in quite a few places in my app.
The window has a timer object (Forms timer, not Threading timer) that has a timer1_Tick callback, which updates one label every tick (to give a stop-watch sort of effect), and updates about 15 labels once each second.
Does anyone have quick suggestions for how to reduce the amount of time spent updating text on a form, other than increasing the update interval? Are there other structures or functions I should be using?
I ran into this issue myself, and ended up creating my own simple Label control.
.Net's Label control is a surprisingly complicated beast, and is therefore slower than we'd like.
You can make a class that inherits Control, call SetStyle in the constructor to make it double-buffered and user-painted, then override the OnPaint method to call e.Graphics.DrawString and draw the Text property.
Finally, override Text or TextChanged and call Invalidate.
As long as you don't need AutoSize, this will be substantially faster than the standard Label control.
Here is my implementation: (Currently in use in production)
///<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);
}
}
If you don't want centering, you can get rid of, or change, the StringFormat.
Well, assigning the Text property takes about 0.6 nanoseconds, give or take. It is the side effects that are expensive. You've probably got the AutoSize property turned on for the labels. So it needs to create the font handle, render the text in a temporary device context, measure the resulting string, taking account for side-effects due to TrueType hinting that artificially stretches the letter shape so it coincides with a pixel on the monitor, also adjusting for the modified ABC metrics to make ClearType work. Then tell the native Windows control that it needs to change its window size. Which will produce paint events for the label as well as the container control that's the parent of the label control. Which goes through the same routine again, now actually drawing pixels. Which, when Aero is enabled, changes bytes in a memory device context which needs to be blitted to the video device driver that actually updates the video memory so that the user can see the result.
Yeah, that takes time.
Speed it up by writing your own code instead of Windows Forms doing it for you. Override the OnPaint event, use TextRender.DrawText to draw the labels. Quick win there, it is easily 50 times faster. Minus the point-and-click convenience of the designer though.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With