I’ve been often asked how to improve performance of WinForms apps so here is the list of my top suggestions and further reading recommendations on how to speed up your Windows Forms applications:
- Reduce modules loaded by your application to increase start-up time. Remove all references from your project that are not used. Click here to read MSDN article on that on other techniques.
- Pre-compile your assemblies using NGEN when appropriate to decrease start-up time. Click here to read my short post with guidelines on when to consider doing this.
- Use native C++ Splash Screen that shows up immediately when your application is started. This will make your application appear to load faster. Click here to read and download C++ project with native splash screen. Native splash screens have such small memory footprint that they appear immediately.
- Don’t set BackColor=Transparent on your controls. Transparent color support in Windows Forms is terribly inefficient since it is not real transparency. Whenever you set BackColor=Transparent you incur additional Paint call on the parent control. As part of child control rendering, child control will first direct parent control to paint itself on it then child control will paint over that so it appears it is transparent. And this is repeated for every single control that has transparent background. Couple that with the next point and you have real slow-down.
- Reduce usage of gradients. Gradients whether linear or radial especially on large surfaces of screen are slow. I know they look good, but use solid colors whenever possible and you will see much better rendering performance. Especially on large panels.
- Reduce code in Form Load event. Use BackgroundWorker to offload work onto the different thread so your UI can load faster and feel snappier while you do other work.
- Delay Control Creation. Creating and populating controls takes lot of time, so if you can, delay it or do it on demand. For example, you can avoid creating controls on all pages of Tab Control right away and do so in either Appllication.Idle event or when that tab is selected from SelectedTabChanged event.
- Set DataSource last. When using data-binding set DataSource property last. If you set it before you set ValueMember or DisplayMemeber properties for bound controls, the data source will be re-queried to populate control each time these properties are set.
- Use SuspendLayout and ResumeLayout on parent controls and form to optimize layout changes. Bounds, Size, Location, Visible, and Text for AutoSize controls causes the layout changes. Note that you should call these methods when performing multiple layout changes and always on parent control of the controls that you are changing layout for.
- Use BeginUpdate and EndUpdate when adding multiple items to trees, grids and other controls that support this.
- Call Dispose() method on your forms once you are done with them. Most of the time developers forget to call Dispose() method on form they’ve shown using ShowDialog(). Make sure you always dispose your forms and controls to free up memory. Use handy using statement.
- Dispose() your graphic resources. If you are performing any custom drawing make sure you explicitly dispose your Pen, Brush, Image and other graphic resources once you are done with them. Using statement is good for this as well.
Do you have more tips for speeding up the WinForms application? Please share them in comments below.
Also check out the 2 Things You Can Do Today To Improve User Interface In Your Applications post for helpful UI tips.
[…] Forms Applications Retweeting @DenisBasaric: 12 Tips To Speed-up Your Windows Forms Applications: http://devcomponents.com/blog/?p=361. Very handy list of tips from Dennis Basaric – We use .NET and WPF components made by […]
Hi Denis – do these tips apply to WPF applications as well?
Some of them, specifically 1, 2, 3 and 6. I’ll look into publishing something for WPF as well. Thanks!
[…] 12 Tips To Speed-up Your Windows Forms Applications (Denis Basaric) […]
Perhaps one of the best “tips” articles posted in a long time on any site. I’ll take issue with #3, but only because I think splash screens are a waste. I’d rather the app just load rather than advertise itself. But, that’s just me. I’m glad most commercial apps offer the option of no splash.
Seriously, these are things I know, but as I went through each tip, I realized that I often forget one or two and have to refactor for it. I’m posting it in my cubicle.
Thanks Matt. Yeah, the #3 really depends on how fast your app starts up. I’ve seen apps taking 5-10 seconds to start-up, so in that case at least splash screen shows that something is happening instead of user just double-clicking to start app again because there is no visual feedback that app is starting up. For example I choose not to implement splash screen in TweetPow because it starts up fast and I do all work with BackgroundWorker so UI is not blocked while server is being contacted to load data…
“…to increase start-up time.” I think you meant “to decrease start-up time” correct?
@terry You are soooo right. Thank you for letting me know about that. I corrected that blunder. 🙂
Just a question about number 8, as it has cause me a lot of problems before. I just tried again setting the comboBox.DataSource after DisplayMember and ValueMember, and I got an ArgumentException “Cannot bind to the new value member.”.
I have a ComboBox whose DataSource is set at design time to a BindingSource, and I plug the BindingSource to a IDictionary at run time. Setting the ValueMember to “Key” and the DisplayMember to “Value”. How can I set it all in the proper order?
@Noam Gal I have not encountered that. Click here and look through the results, perhaps something is solution there.
When I tried:
cmbDistricts.DataSource = districtsBindingSource;
cmbDistricts.ValueMember = “Key”;
cmbDistricts.DisplayMember = “Value”;
districtsBindingSource.DataSource = controller.GetAllDistricts();
I got the above exception at run time.
I then tried:
cmbDistricts.DataSource = districtsBindingSource;
districtsBindingSource.DataSource = typeof(IEnumerable<KeyValuePair>);
cmbDistricts.ValueMember = “Key”;
cmbDistricts.DisplayMember = “Value”;
districtsBindingSource.DataSource = controller.GetAllDistricts();
And it worked like a charm for me.
Crashed just the same on a different computer. Can it be because they have an older version of .NET 2? not sp1, for sure. Mine has sp1.
I reverted to setting the DataSource first. At least it works.
it’s
districtsBindingSource.DataSource = typeof(IEnumerable<KeyValuePair>);
sorry.
the comments here butcher the code. it’s a KeyValuePair of string, string in there.