I have a WinForms application. the main form is has a lot of controls and that is one of the reasons that makes it load very slow. what I would like to do is to make the form load faster.
I have set the beginupdate and endupdate. The form is not being rendered in the background worker thread, because this is the main form. There are no initial forms. When the user clicks the application icon, this is the first form that loads up. Adding a progress bar or any splash form is not a good idea for me.
I have checked other questions here on Stack overflow but they do not seem to face the same problem as I do.
If there are some examples/ideas you have in mind, it would be nice of you if you can share it with me.
A few suggestions:
Try to minimise the complexity of your UI. Your users will thank you and you'll have fewer controls to load. For example, if you have 3 or 4 controls that are not used often, can you move them into a dialog or fold-out "advanced" section of your form, so you can defer creating/showing them? Are all the controls needed? Really? Think about the workflow you are trying to achieve - is the current set of controls the simplest way to achieve the workflow? DO all the controls need to be shown at once? Perhaps you could place them on to separate tabs in a tab control (and thus only actuallyl create the controls as the tab is shown)?
Can you reduce the range of control types used? Each new type of control may cause your program to load up a new dll to support it. Every dll that has to be initialised causes extra startup time.
Are you using any controls that are slow to start up? A simple text field will be fast, but a complex graphing control may be slow.
How many assemblies (of your own) are loaded? Combine all the code into a single assembly (e.g. with ILMerge) and load times will probably improve quite a bit.
Remove any initialisation code that isn't needed. Can you simplify the initialisation? Can any initialisation be deferred (e.g. only create some member variables when the user clicks on the first button that actually needs that data to be present, Don't try to create a connection to a database if it's not actually needed yet, etc)
Can you defer creation of (some of) the UI? For example, you may be able to place a group of controls into a separate UserControl form, and then add this form programmatically to your MainForm shortly after startup (e.g. on a Timer). This will allow your MainForm to appear very quickly, and then be "populated" shortly after with additional controls, which may not improve the actual startup time, but it will "feel" a lot faster and more responsive to start up. (This approach can also be extremely effective if your MainForm scrolls and those extra controls are initially not on-screen, as they only need to be created if the user scrolls down enough to see them)
Are you displaying any information that might be slow to load (e.g. large bitmap images or data fetched from an SQL server)? Can you defer the loading of them or run it as a background thread? Use compression to speed up loading? Reduce their resolution to minimise the amount of data that must be loaded? Pre-process data and store it in a quick-start cache for the next time the program is run?
Can some controls be replaced by an optimised approach? e.g. You can create a "button bar" as a set of 10 separate controls, or as a single control that draws iself with the appearance of 10 buttons. It's much easier to make the single control initialise and redraw faster than 10 separate controls.
And of course, once the most obvious low-hanging fruit has been collected (or even before):
Run the program under a profiler and see where it's spending its time.
Try to minimize the code that executes during on load of main form or any of the control that is placed on the main form.
You can also explore NGEN which is Microsoft's tool which helps in improving managed app's performance
When a form loads it initializes all its controls.
The Form itself isn't taking you a long time.. It's your controls.
Go over your controls and check what can be improved in their constructors and initializers.
Do you need all of the controls immediately? If not perhaps you could load them programmatically after some event fires that lets you know you need that control.
If you have several controls to a parent control, call the SuspendLayout method before initializing the controls to be added.
After adding the controls to the parent control, call the ResumeLayout method. This will increase the performance of applications with many controls.
For example:
private void LoadData()
{
// Suspend the form layout and load the data
this.SuspendLayout();
LoadMyData(); // logic to load your data will be here
this.ResumeLayout();
}
EXPLANATION:
SuspendLayout() - Stops the layout object from being updated and thus the component does not spend any time making calculations for repainting until the layout is resumed.
ResumeLayout() - Recomputes the layout once after all of your changes are made, resulting improvement in performance.
Why use SuspendLayout() and ResumeLayout()
It prevents layout accidents when controls have layout properties that affect each other.
It adjusts multiple layout-related properties like Dock, Auto-Size etc.
Related
So my problem is this. I have a form with a panel in it. This panel serves as the container for multple different usercontrols, of which only one is visible at a time. Some of said usercontrols display a lot of data from the DB, so loading them takes a little bit of time (the data is shown in a bound datagridview). I tried creating a LoadData-method for these controls that I then launch in separate threads and once they've done their work, they enable the actual buttons on the main form for displaying them.
There were, however, many different problems. First, I can't call this.Invoke on the usercontrol until its handle is created, which seems quite hard to force, especially if I want to show a splash screen during the initialization (the main form's handle isnt created yet).
I did manage to force this by setting the form.Visible = true and then calling form.CreateControl followed by form.visible = false. This does, however, show the form blinking on the screen which doesn't look nice.
I also tried not using Invoke if the handle is not yet created, but this brings me to the problem of my data object being created in a different thread and then not being accessible for the control's "normal" thread.
So as is probably quite obvious, I'm quite lost when it comes to multithreading, especially so with winforms, and even more so at the launch of the application. My explanation might also be rather confusing, but I'll try and clarify if it's needed.
So what is the correct way of doing this?
Hard to know where to start with this.
Can't figure out whether your problems are premature optimistion, or trying to retro fit multi-threading.
If I had say a six buttons and one panel and the buttons flipped a usercontrol in the panel to visible, My thread would return a user control, which I'd then add to the panel and then enable it's related button.
Takes all the synchronisation stuff right out of the equation, and gives you maximum scope for optimistion the getting and setting up of the controls.
Or you could setup all the user controls but not bind them and get your threads to bind on completion, I prefer the former way though, a bit more abstraction and you could get to define a view, mark it up with some useful attribute and just get you main form to kick off a process which would "just do it".
I am working in a Windows Forms application, it needs a lot (and I mean a lot) of controls. Using tab controls to organize them (sometimes nested tab controls).
I was reading how to load the App faster and a lot of people said to think twice if the controls are really needed. Well, to be honest I think that it's possible to reduce the number of controls used BUT the client requested it that way, so there's almost nothing I can do about it.
I was reading that I should use multithreading tactics but there's a hardware limitation: the application MUST run on an average neetbook. It's really a pain because I'm limited in terms of load time and how much space I can use to put the controls.
I was wondering if I can just load one or two tabs before the form is shown and then load the others, would that be possible/correct/efficient? If it is, how could I achieve it? I also was planning to use MDI childs but I need to retrieve all the information in all the controls at some point (from absolutely all the tabs and nested tabs).
Can you please give me some tips? Do you have any experience working on something similar?
One strategy is creating your main page with a TabControl holding empty TabPages.
Then you can design several auxiliary forms (one for each TabPage you require) each containing a single Panel control with Public visibility (change the Panel's Modifiers property to Public) holding the real UI elements that you would have placed on the TabPage.
When the empty TabPage is clicked by the user, then you create the auxiliary Form (you don't show it, just create it), and then access the Panel control in the auxiliary Form, then you can reparent it to your empty tab Page, like this
AuxForm1 frm = new AuxForm1();
frm.MainPanel.Parent = this.tabControl1.TabPages[0];
This will delay the TabPage's control creation until the panel is clicked by the user :)
Hope this helps!
I was wondering if I can just load one or two tabs before the form is shown and then load the others
You could make each "tab" contain a UserControl, and load that UserControl on demand, when the tab is activated. That would, at least, prevent you from having to initialize everything on startup.
"lots of controls" is not a requirement anyone can answer. A dropdown list with tens of millions of rows is a very different problem than a wizard UI with thousands of steps and require different answers.
Why has the client "requested it that way"? We need to know the actual deliverable requirements to answer your question. Have you shown them alternatives?
First, post some of your mockups. If you don't have mockups yet, make some and perform paper testing with them, then post them.
Who's "a lot of people"? Testers? Customers? Anonymous forum posters? Post your mockups to https://ux.stackexchange.com/ and ask for comments.
"I can just load one or two tabs before the form is shown"? Of course you can do that, but why are you presupposing that your UI will be "one or two tabs" before you have shown us any requirements at all? Get requirements, make mockups, then ask specific, answerable questions.
I have a WPF application (.NET 4) which has a main window, and inside that main window shows many smaller UserControls. Various actions performed by the user cause the UserControls which are displayed to get replaced by different other controls with different data.
I am running into performance problems however, when switching these controls. The WPF dispatcher thread goes to 100% CPU while loading controls. On older machines, or with larger numbers of controls, this can result in the application appearing to lock up for as long as 30 seconds!
Profiling indicates that almost all of this CPU time is spent calling the various InitializeComponent methods of all the different UserControls - no one control appears to be vastly worse than any other, they all seem to take between 0.2 and 0.5 seconds (on my dev machine with a fast processor and good graphics card).
As far as I know, InitializeComponent is where WPF actually loads the compiled xaml into memory.
I'm at a loss for what to do here. I'd like to pre-initialize things on a background thread, but all WPF controls must be created and used on the dispatcher thread, so I don't think this is possible.
Otherwise it looks like the only options I have are to delete all my xaml??
Any help would be greatly appreciated
To revisit this - we do have many complex controls on the screen, but we can't just get rid of them to keep WPF happy!
Further experimentation with profiling showed that using Custom controls (basically just a C# class deriving directly from Control and defining the UI in a Generic.xaml themes file only seem to incur the hit of loading and parsing the XAML once. Thereafter, each control just applies the pre-existing theme.
Custom controls are much more difficult to work with than UserControls, but this did seem to help our load performance a lot.
The InitializeComponent method takes time because it needs to insert the control in the Visual/Logical tree and assure all bindings, themes, expected resources etc.
My only suggestion is - is it possible to initialise all potential controls from the outset, and then show/hide them when needed using the Visibility property ?
You can use Freezable for caching some UI, but if they are user controls then most likely you will want your user to interact with them.
For the record, I had a window with a load time about 1500 ~ 2000 ms, the problem was the icons.
I was using a tool for converting SVG to XAML DrawingImage elements, and a user control with a large resource dictionary with a drawing image for every used icon
The InitializeComponent was so slow because it had to parse that large XAML file containing all the vector data for the images
Hope it helps.
My form has over 200 control(s)!
It takes about 7 seconds to load the form and bind the controls.
I've traced the application with some performance profilers , but I didn't find anything with HOT flag except the constructor's of form.
I would like to know that is it possible to call InitializeComponent method with sth like backgroundWorker (multithreading) !?
No, threading will not help you. The controls need to get created on the UI thread for the application to work at all.
The only reasonable way would be to look into whether you really need to create all 200 controls when the form is created, or if you can perhaps have them load "on demand".
Without knowing your application it's impossible to give more concrete guidance, but perhaps you have a situation where not all controls are in use at the same time, but rather that there is some sort of paging. If that is the case, each "page" could perhaps be made into a user control, so that you can load and unload pages as they are needed.
A better idea would be to split your UI up using a TabControl. It has lazy loading built in.
Per MSDN :
Controls contained in a TabPage are not created until the tab page is shown, and any
data bindings in these controls are not activated until the tab page is shown.
And that design is directly aimed at your problem.
Performance isn't your only problem. There are OS limits on the number of handles a process can own, and there are limits on the nested control layout WinForms will perform. If you have 200+ Windows Forms controls on a single window, I'm betting you're going to run into these and other limits.
I recommend changing your Form so that there are fewer controls: paging, virtualization, lazy loading are some techniques you can use to improve your UI and your performance.
Things to try that others haven't mentioned:
Take the [DebuggerStepThru] option off of InitializeComponent, then you may see which items are taking long more easily (w/ profiler or just randomly hitting 'pause' in the IDE during load 20x and remembering where it stops most).
Convert to WPF if your boss will let you.
Take the forms InitializeComponent's items, outof initialize component and on clipboard. Add a timer w/ 20MS ticks. On tick, increment a counter. Add one control per tick, by splitting your initializecomponent code into a 200-case select statement. At 201 stop the timer. That way the user can start working before all the controls are added. You will have to rearrange the controls.add so they show up. You will have to show the important controls first. You will not be able to modify your form in the designer. Lastely, I pity the foo who thinks this bullet point is anything but a joke.
I believe NGen-ing your application can help the performance a lot. Most of those controls (some of them possibly custom in your application) need to be NGen-ed and that usually takes a long time, as going back to the same form is always much faster.
While I might agree with Judah, I have seen plenty of forms in an MDI WinForms app that far exceeded 200 total controls logically contained in a form, and the form needed every one of them to do its job. An invoice entry window for instance would have a set of controls for a header, then a set of user controls that each mapped to an invoice line and had fields for SKU, description, quantity, unit price, extended price, unit tax, etc. Such a window's control count depends on the number of invoice lines, and a large order can generate an invoice requiring thousands of controls to be bound and rendered on a single screen if done naively. Add in further per-line detail for shipping instructions, tax information, backorder status etc. and attempting to pre-load and render every control on window load would crash the application.
7 seconds seems excessive, though. I agree with Frederik; the first step is to look and see if all 200 controls have to be rendered in order to show a single screen's worth of information. Using tab controls, with event handlers for tab changes that "lazy-load" the information and controls shown on each tab, is a good first step. If you show lines of repetitive child information (like invoice lines on the invoice) you can save time by loading a finite page of information at a time; loading 10 lines is far cheaper than loading 100, and while there is some overhead in talking to a DB and dynamically loading controls that will be repeated more often this way, it will seem trivial compared to waiting several seconds just to see ANYTHING load on the window.
Facing an issue where in the user objects goes more that 10000 in windows app and the app crashes.
After much analysis we realized that we need to get rid of the panels that we use to align the controls and may be reduce the possibility of user objects reaching 10000.
Our App UI is dynamically generated driven by a configuration and it can vary. So all the UI generation is happening dynamically.
Any help would be much appreciated
This is an unfounded suggestion, but remember to make sure that unneeded Controls always detach themselves from events they are be subscribed to. A Control that's still subscribed to an event of an "active" (what's the right term?) object can't be cleaned up.
Just as a note, the Chrome development team hit this problem too, and the scroll bar arrows (among other things) weren't drawing anymore when some internal gdi limit was hit. It is quite possible to hit this limit in a complex enough gdi app.
You might want to do some research and see how they fixed it.
As an alternative, you could consider using a different platform, either gtk or wpf would do fine and they don't use gdi handles to draw.
from here,
If your program runs haywire, you will
find that it manages to create about
10,000 window manager objects and then
the system won't let it have any more.
Why stop at 10,000?
The first answer is "If you have to
ask, you're probably doing something
wrong." Programs shouldn't be creating
anywhere near ten thousands window
manager objects in the first place.
There is no need for that many handles. I think you need a new solution.
I'm guessing this from your question, but you're probably putting this large number of controls on a scrollable panel or a tab control with multiple tab pages, which means that most of these controls aren't actually visible to the user at any given point in time (because they couldn't possibly all be visible at once).
If you have all of these controls on a scrollable panel, one possible solution is to only load and display the controls that are on the visible portion as the user scrolls around in the panel. As the user scrolls, you would unload and dispose the controls that are no longer visible.
If you have all of these controls in a multi-page tab control, you can use a similar strategy and only load the controls on a tab page when that page is made visible (and unload the controls from the previous top-most tab page at the same time).
Another general strategy is to break up your one monster form into a large number of UserControls, and only show one of these UserControls at a time.