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?
Load: This event occurs before a form is displayed for the first time. VisibleChanged: This event occurs when the Visible property value changes.
The Load event occurs when the handle for the UserControl is created. In some circumstances, this can cause the Load event to occur more than one time. For example, the Load event occurs when the UserControl is loaded, and again if the handle is recreated.
Activated: This event occurs when the form is activated in code or by the user. Shown: This event occurs whenever the form is first displayed. Paint: This event occurs when the control is redrawn. Deactivate: This event occurs when the form loses focus and is not the active form.
Load Event (System. Windows.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With