tags:

views:

44

answers:

2

I have a variety of small C# winforms applications (though this should apply equally to any .NET app) which need to perform a few minor tasks when they are closed.

I have been making use of the .FormClosing event to do things like write the current settings file and wait for background threads to finish, etc.

Two questions came to mind about this as far as best practices go:

  • Do I need to stop timers (or similar tasks) when closing a form? Knowing that terminating the app should dispose of the timer, is it a good idea to issue a timer.Stop() in the closing of the form? Is it possible once having entered the .FormClosing method that the timer could trigger again?

  • Should last-minute tasks, such as writing a settings file, be in the .FormClosing or .FormClosed event (or elsewhere) and why?

Sorry for combining these questions but I felt they were related closely enough to warrant a single thread about properly closing a form-based app.

+2  A: 

Should I stop a Timer?

Not really but it won't hurt either.

Could a Timer trigger after FormClosing?

Tricky. Not normally, but if some code in the Closing chain calls Application.DoEvents() I wouldn't rule it out. Always a good idea to program your Timer-handler defensively.

Should last-minute tasks be in .FormClosing or .FormClosed ?

FormClosing is conditional, its main function is to show a "Save first?" box or similar. I would put everything in FormClosed unless it really needs to be earlier (ie it requires other components/controls to be alive and active).

Henk Holterman
@Henk: +1 Helpful, thank you. As an example, the settings file records the location of the form to restore when it is next launched. Wouldn't the `Point` of the form be inaccessible in `.FormClosed`?
JYelton
I think Location is still valid but you'll have to check it out.
Henk Holterman
+2  A: 

to warrant a single thread

Well, you already answered your own question :) Events like FormClosing and a timer's Tick event all run on a single thread. There is no way for a timer to "break" into a thread and run the Tick event, your thread is busy doing the cleanup stuff. The Tick event won't run until your thread goes idle again when it completes running the event handler and re-enters the message loop.

But before that happens, the form will destroy itself, disposing all its controls and components. That puts an end to any opportunity for a timer's Tick event to run. There's no need to explicitly Stop() it.

This won't be the case for a System.Timers.Timer or other asynchronous components like BackgroundWorker. It is very important that you stop these before your form closes. If you don't then your code will typically bomb on an ObjectDisposedException. Especially System.Timers.Timer is very hard to stop, it can schedule the thread that calls the Elapsed event handler a microsecond before the user closes the form. Big Kaboom when that happens. Don't use it.

Hans Passant
"Don't use it", agreed, but if you do want it, just make the handler a little more careful. Check the state of the Form.
Henk Holterman
'State of the form' is a mine field, a property like IsDisposed isn't synchronized. The Form class unapologetically passes the burden completely onto the programmer.
Hans Passant