How do I know when all controls have loaded and displayed? - c#

What is the real order of events in a Windows Forms application?
What I mean is, when I put code in the Form_Shown event, I expect that code only to run after the form has been Shown:
verb (used with object), showed, shown or showed, showing. 1. to cause
or allow to be seen... - http://dictionary.reference.com/browse/shown
But the Form_Shown event is a little misleading. If I do some heavy stuff inside that event, it seems as though the code gets executed before the Form has finished been shown. Let's say that I have a MainMenu, a small Toolbar and a TextBox on a form.
I want to do some heavy stuff (nevermind threads and workers for now...), so the last event I can use I would think would be Form_Shown. So I put my heavy code in there, but when the Form begins to display, I end up waiting ~ 5 - 6 seconds for the Toolbar and stuff to display (which ends up happening after my heavy code does its thing.
Which leads me to believe that I'm subscribing to the wrong event. I don't want the Form_Shown event at all. What I really need is:
Form_WhenALLTheThingsHaveShownEventHandler event.
So, how can I know _when all the things (controls) have been fully loaded and displayed?

The Shown event is in fact the last event related to initialization that is raised. However, note that the actual rendering (drawing on-screen) of UI objects in Windows (and on other platforms) is deferred. The creation of a UI object merely allocates all the necessary resources and "invalidates" the visual area of the object. The platform then later schedules the rendering event (in unmanaged Windows, this is WM_PAINT, in the Winforms API this would be the Paint event for a Control instance).
The rendering event cannot be dispatched until the UI object's thread is available, and if you have long-running code in the Shown event, that will keep the UI object's thread unavailable for the duration of your code. I.e. nothing gets drawn until your code completes.
There are other events that you could use to more reliably detect when things have "settled down". For example, the Application.Idle event tells you when the main application thread is about to enter the idle state. Alternatively, you could just subscribe to the form's Paint event. In either case, you would want to use BeginInvoke() to dispatch your long-running code, so that you don't block the handling of those events.
Now, all that said: you really should not be performing any long-running work in the UI thread, period. Using either of the above events doesn't solve the underlying problem; it simply delays the problem until after the initial rendering of your UI. The UI will still remain blocked while your long-running work is executing, and frankly the user may actually find it preferable for there to be no UI at all, than for there to be something that looks like they can interact with but which they can't (i.e. is unresponsive to their input).
In the latest version of .NET, there are some very nice mechanisms available for shifting long-running work to background threads, so that the UI can remain responsive. See Task and the async and await keywords in C#. You could instead use the older BackgroundWorker object to accomplish the same, if you prefer.

Related

Execute code when form loaded and before Form closes

I'm currently working on an application that uses a Windows Form GUI. The main work of the application will be performed on an additional thread - but it is possible that it will be dependent on the state of the form.
Because of this, before I create the thread I must make sure that the form is completely loaded. Also, I need to make sure the thread is terminated before the form begins closing.
Possible solutions for this problem might be overriding the OnShown and OnFormClosing methods.
Does the OnShow method really gets called only after ALL of the assets of the form have been loaded? And what about the OnFormClosing - can I be sure that any code executed in this method will be performed before the form begins close / dispose?
I suggest you read through the WinForms event ordering as posted on MSDN:
http://msdn.microsoft.com/en-us/library/86faxx0d.aspx
Windows Forms events can be tricky, and the order they fire unreliable. For example, the 'Shown' event is meant to fire once and once only, when the Form is first displayed, but just yesterday I found a way to completely prevent that event from firing by manipulating Form.Visible flags at the right time.
So, you need to be quite specific about your needs. For example - when you say 'completely loaded', what do you mean? Controls created, form visible, Form constructor finished executing?
Likewise, the FormClosing event might be circumvented by an unhandled exception in your main aUI thread, which results in the Form being removed without the event firing.
I suggest never assuming anything around these events. Make your worker thread capable of dealing with the Form state being unavailable, or not ready. Without knowing your exact requirements, it's hard to be more specific.
Have you tried to use InitializeComponent on the constructor of your main WinForm and use OnLoad (called whenever everything is loaded)?

how to detect if the UI Thread has finished working in WPF

I need to measure the performance of WPF multi-threaded application, what happens is following:
1. buttonClick is triggered in UI -> the UI thread starts processing it
2. UI thread starts another threads in background, which asyncronously do something in background and, when ready, pass the result back to the ui thread
3. Data binding occurs
4. Rendering occurs
The amount of threads is known to me, the order is not.
How could I measure the time between the buttonClick and the end of the rendering? Is the UI thread firing an event or raise a property when it has finished? Or if not, can I make it?
Any help would be apprechiated.
I found something possibly helpful at http://www.kynosarges.de/WpfPerformance.html:
We cannot directly access the rendering thread but WPF does offer one
indirect point of access, namely through the
CompositionTarget.Rendering event. This event usually fires at the
monitor refresh rate (typically 60 times per second), whether there’s
any new content to render or not. It is primarily intended for custom
animations that need to generate display updates as quickly as the
monitor can show them.
You have to look on WPF Performance Suite, especially on Perforator and Visual Profiler.
On VisualProfiler you can have "Application CPU usage details" section one of which is:
Render (MediaContext) Occurs during the render pass. This method
eventually calls the OnRender method of each element, and is useful
for understanding the total cost of OnRender for all elements....
or
Rendering Thread Occurs when executing rendering instructions on the
rendering thread. This is useful for detecting render-bound
applications.
Hope this helps.

Is there an 'Application.DoEvents' at the form level?

I currently have an application that spawns multiple instances of a single win form. Each instance of the form has a timer which updates a number of controls and some of the properties of the form itself at rate of approx 1 tick/sec. Once the application reaches a certain number of forms it stops painting the 'updates' that occur within the timer ticks.
I want to hold the UI thread at the bottom of the timer and allow the form to repaint without calling Application.DoEvents (my understanding is that Application.DoEvents() handles all pending window messages across the application (which could include other timers 'ticks'? - not sure) when all I want it to process is the redrawing of the form now that a number of the controls have been updated).
It's not clear to me why you want to call DoEvents at all. Why not just let the window repaint itself appropriately? What's wrong with the way it behaves at the moment?
Calls to DoEvents usually indicate that something should be in a background thread - in your case it sounds like it might actually just be that you've got too many events going on. If your GUI is so complex that it can't redraw itself in a second, it sounds like that's probably a design issue with the UI itself.
If you just want the form or a specific control to redraw itself, just call Control.Refresh on the form/control in question.
That being said, this is usually (like Application.DoEvents) a sign that a redesign is in order. If you have long running processes like this, it's a much better idea to push the work into a BackgroundWorker, which will make the actual computational work run in a background thread, and prevent the UI from becoming unresponsive.
There are three categories of Windows messages that are dispatched by the message loop and a call to Application.DoEvents(). First are messages that are sent with SendMessage(). They are important, they need to be dispatched right away because there is some other program waiting on the result of the SendMessage() call. They are not put on the message queue, Windows calls the window procedure directly.
Then there are messages that are put on the message queue with PostMessage(). They can wait, they are merely notifications. All of the keyboard and mouse messages fit that category.
Then there are the low priority messages, WM_TIMER and WM_PAINT. They only get dispatched when there's nothing else to do, no SendMessage is pending and the message queue is empty.
Sounds like you got yourself into a situation where you starving Windows so badly that it can't get around to dispatching those low priority message anymore. Probably neither getting timer Ticks nor Paint events anymore. Calling DoEvents only once a second will certainly do that. This is bad, your program is now affecting the operation of other programs as well. You'll have to fix that. Do so by re-architecting your app so you no longer depend on DoEvents.
My 2c:
Having a timer in each form is going to slow down performance to a crawl. Each window at each second interval is going to request the application to switch to that window's "context" and execute some code. That whole switch is likely longer than your code actually takes to run. Couple that with the likely fact that all of your forms are in the same "context".
Instead consider something like this if possible:
List<MyForm> listofmyform;
Timer t = new Timer()
t.tick += delegate
{
foreach(MyForm thisform in listofmyform)
thisform.DoUpdate();
}
This only uses one timer to update all of your forms, only requires one "context switch" and will likely cure some performance problems you're having.

Use the UI thread of a WPF application to do a long processing task on a UI element, but also update a progress bar on the same window

My program consists of a large graphing UI control that I need to spend about 15 seconds re-loading every once in a while. Because the updating code works primarily with the UI control (maybe 90% of it actually sets properties on the control), it would make sense to me to actually let the UI thread handle that. I really don't want the control to visually re-paint while it is loading in a separate thread from the UI.
I also want a progress bar to update as well that lives in the status bar of the same application window. Is there a way to break the rule in this case and re-paint only the progress bar, or should I just open a new application window for the progress bar to live in?
What would you do in this particular case?
If you can break your primary task (ie. updating the graph) in many steps, you can perform each step as a separate dispatcher message. This will allow other messages to be processed, including giving you the ability to update progress information.
The basic pattern is:
Invoke your primary task, passing in zero for the step.
Perform the step.
If there are more steps, queue another message, passing in step + 1.
You can then add in progress updates at the appropriate points in your code.
PS. Not saying this is your best option - hard to tell without knowing all the details. But this is an option.
It is not really true that there is only one UI thread in an application, it is just that most windows applications only ever create UI objects in one thread so this thread becomes "the" UI thread in the application. It is easy to understand why - this makes the code simpler to understand, and protects us from implicit thread binding issues between controls.
This suggests a possible idea, should it prove impossible to improve the speed of updating the control (which is what I would suggest to do first). Create the UI control on a separate thread. You need to make sure that the thread is suitable for UI, that is to say the threading model is STA, and that it will pump messages and not die before the control is destroyed. I don't know if you need to create the parent window in the UI thread as well, or just the control but it may be worth experimenting here.
Find a graphing UI control that is more efficient. Unless the UI thread yields to the message loop any other updates won't happen (and it will slow down your graph control's updates).
I would suggest using a progressbar in a new window (without the form headers). Make it paint the progress bar by reading the shared properties of a graph control. this way you can avoid the thread blocking (sluggish loading).. And it gives you good visual experience (progressive painting on both the controls).

C# Winforms How to update toolStrip in function

I'm building a UI for a program, and I can't figure out why my progress bar won't become visible after the convert button is clicked.
private void convertButton_Click(object sender, EventArgs e)
{
toolStripProgressBar.Visible = true;
...
toolStripProgressBar.Visible = false;
}
I ran into a similar problem with tkinter in Python, and I had to call a function to update the idle tasks. Is there a way to do this with windows forms without using threads?
Edit: On a side note, this is a progress bar in a toolStrip that also contains a label that gets updated with status bar text. Is there any way to get the label on the left side and the progress bar on the other instead of right next to each other on the left?
Well, there is a way to do this without using threads (Application.DoEvents) but I strongly recommend against you using it. Re-entrancy is nasty, and you really don't want the UI thread tied up at all.
Use BackgroundWorker instead - it's easy, and it's pretty much designed for progress bars. It takes the hassle out of using a separate thread and reporting progress back to the UI thread. No need for Control.Invoke etc - it takes care of that for you.
There are lots of tutorials for BackgroundWorker - it shouldn't take you too long to get going with it.
Per the question you asked for the way to do this WITHOUT threads, that is to do it with Application.DoEvents();. (Just add that call right after setting the progress bar as visible.)
Now I do agree with Jon Skeet though that BackgroundWorker is a better way of doing this, but it does use a separate thread.
You need to execute your process in a thread separate from the UI thread, and then have it periodically report back to the UI thread with it's progress. If your convert operation is working inside the UI thread, it will simply go unresponsive until the operation is complete.
The progress bar can only become visible when it is allowed to paint which occurs during the processing of messages. Message processing cannot normally happen while you are in the middle of an event handler. If you want the progress bar to show up you will have to set the visiblitity to true, start a background thread to complete the work and return from the handler.
I'm guessing the problem is that the "..." in your code is a long-running process. UI updates are not instantaneous, but must run through the message queue in windows and then be painted to the screen. The queue is pumped and painting takes place in the same thread as your events.
As a result, any long-running tasks need to be moved to a different thread. More than that, your line line of code needs to called after that thread terminates. Otherwise you set the progress bar and then immediately turn it off again.
One way to do that is with a BackgroundWorker control.
Here go two links trying to explain you how things work:
(1) (2)
Now, I will try to explain it as shortly as I can. Most of what happens inside a windows forms application happens in a single thread, usually the same thread Main() runs in. If you open Program.cs, you will see that Main() has a line that looks like the following:
Application.Run(new Form1());
If you debug the application at any moment and examine the call stack, you will see it will trace back to that Run method. This means that a Windows Forms application is in fact a continuous run of the Run method. So, what is Run doing? Run is eating a message queue through which Windows sends messages to it. Run then dispatches those messages to the correct controls, which themselves do things like add text which corresponds to the key being pressed, redraw themselves, etc. Notice that all this happens during and endless loop running alongside a single thread, so weather you are typing or simply moving the window around, loads of those messages are being passed onto the application, which in turn is processing them and reacting accordingly, all in that single thread. Controls can also send messages to themselves through the queue and even you can place messages in the pump via Control.BeginInvoke. One of the things those controls do is to raise events according to what happens. So, if you click a button, the code you've written to handle that click will ultimately and indirectly be run by the Application.Run method.
Now, what is happening with your code is that even though you are changing the visible status of your progress bar to visible and then updating its Value, you are then changing its visibility to false, all in the same method. This means that only after you leave the method, will Application.Run() be able to continue iterating and consuming the message queue, effectively asking the progress bar to update its display. When that happens, you've already left the progress bar's visibility to false, the last thing you did before exiting the method. DoEvents() is a quick and dirty workaround to your problem as it reads the messages in the queue and processes them. I don't really feel comfortable using it as it can bring reentrancy problems.
Using threads is a good solution, but I would recommend using a ThreadPool thread instead of a custom thread in this kind of situation, as I tend to use custom threads only in cases where I have a limited number of long lived threads and I need to control their life cycles. The easiest and most practical way to use threads is to use the BackgroundWorker component, even though I would recommend going through the pains of understanding how to do Windows Forms multithreading with delegates if you want to really understand what is going on.
My solution is to call refresh on the status strip.
I believe this causes the UI thread to repaint the status strip.
toolStripStatusBar1.PerformStep();
statusStrip1.Refresh();
This is for .NET 4.0. Even though this question is old it was the first I found on googling this issue.

Categories

Resources