Concurrent data loading with winforms - c#

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".

Related

Dynamically adding lots of Controls form another thread

I am learning multi threading in Win Forms using C# and according to sources the best way to achieve this is by invoking the main method from worker threads.
Now this all works good when heavy processing must be done and THEN the GUI is updated.
However I have a scenario where I need to programmatically add lots of controls inside a panel. This may go up to thousands (panel will be scrollable). Hence, since the controls are ultimately being added by the main thread, the program still hangs until this has been completed.
Is there any way around this? Or should I try and use some other control which doesn't require me to instantiate lots of controls simultaneously (as this is obviously a bit heavy).
Basically this panel contains a list together with an icon (depending on the state). Hence I am creating a label for every entry which I do not know if it the ideal way.
By the way I come from the web applications development department... Is there a control similar to a div in .NET? I looked at a rich text box but it doesn't seem to let you add an image in a straightforward way.
Thanks in advance.
You shouldn't have a good reason to add hundreds of controls, let alone thousands. It sounds like you need a custom control and you need to add items to it.
The ListBox or ListView control will work for a basic item but if you want lots of customizability you will have to reinvent the wheel yourself and draw everything manually. It's a lot of work if you need to handle multiselect, scrolling, keyboard shortcuts, etc.
This is the strength of using WPF instead of Winforms since you can easily use the existing ListBox logic and have free range to customize the appearance of the items and even how they are arranged.
WPF has the concept of a virtualizing panel which can perform well even with thousands of items since it doesn't create the UI objects until an item is scrolled to.

Best way to load a heavy UI with lots of controls

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.

How to improve the loading time of winform?

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.

How can I detect the visibility of a control?

How to detect if a control is visible to a user? I have a control that displays status of application, and I want it to be updated (it's value to be updated, for example, increase the value of a progress bar, or change a label's Text property) only if a user sees it. No need to update it if a user has minimized the form that contains this control, or if another form overlaps this control. I just don't want to do extra calculations if the control isn't visible any way.
Also, how do I detect the events that hide/show this control?
This seems to be one of the topics which is frequently asked and which has many possible solutions, depending on the context.
First, for reference sake, some links to old discussions I stumbled over during my research:
How to check absolute control visibility and how to be notified for changes of absolute visibility
C# winform check if control is physicaly visible
starting position:
An IDE for heterogenous systems with plenty of different hardware and many different transport layers where some are really slow. One feature is to display memory values of remote hw in editors. A typical use case is to have >20 editors open, where each displays between 1 and 100 different values.
Because the transport layers are limited in bandwith I was looking for a solution to "prioritise" the data acquisition.
(partial) solution:
A visibility tracker which basically manages a specialised adapter for the control itself and every ancestor control. The adapter handles the visibility dependent on the ancestors type, ie. for a Control, it's just instance.Visible, for a TabPage I check which page is selected, ...
The manager's housekeeping then is just to keep track of parent-changes for all the ancestors so that it tracks the correct visibilities.
Catching whether or not the form has focus or is minimalized is your best bet, but I am not sure that hits all cases. In general, I would update regardless of whether the user is paying attention, unless it takes tons of cycles to get the information to the form, which I doubt. Setting up conditional bits in an application just adds another place for things to go wrong.
Let's examine this a bit. Minimized forms are one thing. If the form is minimized, you know the user is not even looking at it. But, if another form is in front, then you want to check if the form has focus. the problem here is a person can be using half the screen to watch while typing in word on the other half. Word has focus, so the form does not update, which is not your intention. Same could happen if you create another form in the application. the update no longer has focus.
THere is no magic "is the user looking at me" property in Windows.
This is never necessary. Windows won't generate the Paint event when a window isn't visible. If you implemented painting yourself then be sure to only do this in the Paint event and to call Invalidate() if there's a reason to repaint.
How often does the status change? It is probably better to update the status indicator when the status changes and not worry about visibility. Let's say that status changes on average every 5 minutes. The window/control may not be visible when the status changes but could easily become visible well before the next status update. In this case, the status indicator will be wrong until the next update because you avoided changing the indicator. Unless updating the status indicator is very expensive, it's probably better not to try to project what the user will do.
Edit after reviewing other comments:
I think you might be able to achieve better efficiency improvements by identifying a model for detecting/notifying status changes instead of calculating on demand. You may need to weigh the frequency of status changes against the frequency of visibility changes to your control.
Take a look at Control.Visible, and the Control.VisibleChanged event.

Windows Handle Issue

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.

Categories

Resources