How can I detect the visibility of a control? - c#

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.

Related

How to make a Windows Form to change it height adaptively as controls get added/removed or hidden/shown?

What I need can probably be described as "reverse-anchor", "reverse-dock" or something like that (I have chosen to mention this just because "reverse-anchor" happened to be the first thing to come into my mind as a keyword candidate when searching for questions and answers that might already have been submitted discussing this subject, perhaps this will help people thinking a similar way to find this one in future). WinForms controls implement the Anchor property to set up adaptive resizing on containing control/form size change but I need the opposite - the form to resize adaptively to the controls.
A thing adding a minor bit of complexity to the task is that the controls meant to be added/removed/shown/hidden/enabled/disabled (and resized perhaps - this functionality is not really needed directly so far but I suspect it can turn to be required for compatibility with non-default Windows visual styles and themes that have potential to affect controls sizes unpredictably and can change at any moment of the app running) are not going to be the last ones on the form - a row of buttons will always be in between of the last control of the volatile group and the window lower border.
The actual task is to design a form that will display a collection of objects with a row of controls (a label, a text box and 0-2 buttons) corresponding each of them and it is strongly preferable to use just the very basic "common controls" avoiding grids, lists and stuff like that in this case (wrapping them in an additional container controls like panels is perfectly acceptable though, abstracting them in a separate "user control" can be considered too if this can really make the solution easier, more reliable or otherwise better, using hand-written code manipulating controls and form sizes is perfectly acceptable too (I can hardly expect a "set a magic property and it's done" kind of solution to exist for this task) but I haven't found a reliable algorithm so far (when to change what properties and what formulae to calculate new values with)).
The maximum capacity can be safely limited to something near 10 (or 20, perhaps, but not more - more would be just absolutely unreasonable to display on one form (provided scrolling is not an option)) so both ways are acceptable: to add/remove the controls in runtime or to put them on the form in the designer and just manipulate Visible and/or Enabled properties in the code. By the way I have found a problem with Visible - it gets switched off and back on by the framework internals before the form is rendered and other controls Anchor properties come in the game but I don't think it's a good idea to rely on this to happen always and the same way so just adjusting the form Size property on a control Visible property change does not feel really convenient).
What might be some good ideas relevant to implementing this behaviour?
PS: As far as I know this is a natural feature of WPF but I am to use WinForms to make the app runnable on Macs and, perhaps, other non-Windows platforms with help of Mono.
I'll tell you about some clues may help you:
1- correct to build your own Procedure for manipulating all the matter.
2- i advice to use a Wizard methodology (Next / Back buttons) so if the plate form is small like tablet or smart phone, so the mentioned procedure will decide how many Controls combinations (Label, text box, option button...) will be in each frame of that wizard and keep the remaining for Next button.
3- By the way if you will hide some controls use the original event fires to run the mentioned Procedure. (like a basic button to start the form so don't depend on visible / resize events).
4- Resize the size of each form of the wizard in the last part of the mentioned procedure.
If still a problem exists tell me and i hope i can help :-)

Populating Tabs WinForms Goes Undetected without User View

This might just be a small quirk. But I've built a small windows form application with multiple tabs.
I have a feature that allows users to "load" the entries in each of the tabs by opening a json file. This lets them avoid manually inserting the data. At the same time, I have a "check" to make sure that all required fields have been populated.
What I've found is that even if the load process is successfully populating all the right fields, the user still needs to select each tab (even though they are already filled), in order to avoid hitting the flag.
Hopefully, this makes sense. Right now, my work around is to have the program flip through each tab automatically upon "load", but it seems strange that winforms can't detect a text box has been filled unless the tab is viewed.
Any advice?
Some events only fire when the control is visible. This sounds like what you should do is decouple the text entries from the control and store them in another object which fires off the filled events then do data binding to those entries.
This has the nice benefit of decoupling the UI from the data storage (always a nice thing) as well as freeing you from the vagaries of the .net UI system (both winforms and wpf have 'interesting' quirks like the above which assume specific behavior preferences).

Concurrent data loading with winforms

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

Loading Windows form with over 200 controls

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.

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