I am trying to figure out which I should be using. On closing my WinForm app fires of a Form in Dialog mode. That form runs a Background worker that Syncs the DB with the remote DB and displays it's progress on the "Splash Form."
I have a method like so:
private void CloseMyApp()
{
SaveUserSettings();
splashForm = new SplashForm();
splashForm.ShowDialog();
Application.ExitThread();
//Application.Exit();
}
which is what I call to close my app from Menu --> Exit and in the Form_FormClosing() event. Application.Exit() gives the following error -->
Collection was modified; enumeration operation may not execute.
Now I read that Environment.Exit() is brutal and means there is probably something wrong with your app (see here).
Application.ExitThread() works but I am concered that it may only be APPEARING to work and as I have never used it before I am not sure when it is normally appropriate to do so.
Unfortunately, the problem isn't caused by any of these, and really exists (even if you don't get the message) in all of these scenarios.
Your problem is this:
On closing my WinForm App fires of a Form in Dialog mode. That form runs a Background worker that Syncs the DB with the remote DB and displays it's progress on the "Splash Form."
Since you're not actually shutting down when you request a shutdown, all of the "Exit" functions are trying to tear down your background thread. Unfortunately, this is probably happening in the middle of your DB sync, and an enumeration working in the save logic is probably providing that error.
I would recommend not using any of these - just call myMainForm.Close() instead. That should close your main form, which will fire your closing logic appropriately. Once the main form in your application closes, it will shut down gracefully.
Environment.Exit() is used for console apps.
You want to use: System.Windows.Forms.Application.Exit()
By exiting thread, you are only exiting the current thread context, while leaving any started foreground threads running. I suspect the thread that is causing the error is still running, so you've essentially masked the problem, not worked around it. I would try and figure out why you are getting this error "Collection was modified; enumeration operation may not execute." on exit. It's being exposed by Application.Exit(), but it's not caused by it.
Related
Following are the ways by which we can exit an application:
Environment.Exit(0)
Application.Exit()
Form.Close()
What is the difference between these three methods and when to use each one?
The proper method would be Application.Exit(). According to the Documentation, it terminates all message loops and closes all windows thus giving your forms the possibility to execute their cleanup code (in Form.OnClose etc).
Environment.Exit would just kill the process. If some form has e.g. unsaved changes it would not have any chances to ask the user if he wants to save them. Also resources (database connections etc.) could not be released properly, files might not be flushed etc.
Form.Close just does what it says: it closes a form. If you have other forms opened (perhaps not now but in some future version of your application), the application will not terminate.
Keep in mind that if you use multithreading, Application.Exit() will not terminate your threads (and thus the application will keep working in the background, even if the GUI is terminated). Therefore you must take measures to kill your threads, either in the main function (i.e. Program.Main()) or when in the OnClose event of your main form.
they are all fine.
but form.Close() won't close your application
it closes the form and after that
the main-method returns an int (exitcode).
if you want that your application exits with exitcodes use
Environmet.Exit(exitcode) or return the exitcode in the main-method
Short version: How do I pump for messages while at a particular stack frame so I can wait for a custom dialog to return while blocking, just like Window.ShowDialog(). Ideally avoiding async or multiple threads.
I am creating a custom Notification Dialog for my application which supports a set of different display modes.
It can be used as a blocking popup, exactly like MessageBox.Show, by using Window.ShowDialog(). It can also act as a non-blocking message box by using the regular Show command.
However, I want to have third mode, where the dialog can be shown with a non-blocking call, but then later another call will block until the user closes the dialog. This is so I can let the user know earlier on when they will need to do something, but when the time comes, if the user hasn't already dismissed it the main application thread will block.
Keep in mind I’m not using Async with this.
Basically:
NotifyDialog.ShowNonBlocking(“please remove the device and click OK.”);
//do stuff, wait for processing to complete.
//processing now done, we really need to get rid if the device before the next thing starts.
NotifyDialog.BlockUntilClosed(); //disables main window, starts nested message pump here.
I first wrongly assumed that creating a new Window would create a new thread and Dispatcher queue automatically, so I tried using a condition. Turns out that it doesn't create a new thread. I assumed this because Window.ShowDialog() blocked while the new dialog was shown, but as far as I can tell now it just disables all other windows, and kind of hijacks the message pump (I assume that the stack would look something like main -> message pump -> event that lead us to the ShowDialog() call -> new, hijacked message pump loop.)
Anyway, I would like to reproduce this behavior manually so in my NotifyDialog.BlockUntilClosed() call I can hijack the message pump, disable my main window, and wait for the window to close.
If this isn't possible, I’m going back to the plan of launching the window on a new thread, which there seems to be a handful of articles explaining.
I want to keep this easy to use, so I don't want to depend on closed event callbacks that the consumer would need to use, and my application isn't using Async right now, so I can't await the result.
Alright, figured it out.
The dispatcher has a method called PushFrame. This function is a simple event loop. It's a while loop that won't return until the continue flag on the passed in DispatcherFrame is set to false, at which point it stops processing events and returns.
The solution was to add a member Dispatcher frame to my class, and construct it and pass it to the Dispatcher with the PushFrame call when the BlockUntilClosed method was called. Then, in my Close event handler for the dialog, I set the continue flag to false. Once the Dispatcher finished processing the close event, it detects that the continue flag has been cleared and returns.
There is a fairly good description here:
DispatcherFrame. Look in-Depth
I was created a C# program using 2 forms. I add both of them a exit button with close(); method.But when i run the executable file , even if i close the program with exit button still the program run on processes at task manger. I believe its something related with one form closing but the other one was loaded to the memory and not stopping. Such situations. how come we terminate the complete program without it not storing at memory? close(); method not enough?
There are many ways this could occur. Some of the more common include:
If you use Application.Run() (instead of Application.Run(someForm)) to start the application, it will run until you call Application.Exit or use another method to shut it down. Closing the forms will not shut down the application
If you start a thread, via new Thread, and don't make it a background thread, that will also keep the program alive. Processes will stay alive until all foreground threads have completed. You can work around this by making the thread a background thread (or using the Task class instead of a Thread).
From here Does closing the application stops all active BackgroundWorkers? it seems not.
But from here How to stop BackgroundWorker on Form's Closing event? it seems yes.
So which is it?
(EDIT: I realize that the BackgroundWorkers might exit with an exception. But what's the problem with that? Isn't the point here to not leave running threads which take up resources?)
Closing a Form does not stop all background workers started by that form.
When the entire application ends it will stop all background threads.
Closing the main form (unless you have modified the Main method to do something else) will end the entire application.
Each question you referenced is correct for what it says. If you close the main form, then the entire application will end and the background worker will be closed on its own. If the form that is closing isn't the main form, but some other form, and you want the background worker that it starts to be stopped, then you will need to do so yourself.
It's also worth noting that the second link that you have provided asks for something a bit more complex. It's clear in that post that closing the form (if it's the main form) will stop execution of the background thread. What the OP is trying to do there is to tell the background thread, "hey, it's time to finish up, we're done here" and then have the form wait until that background thread can finish cleaning things up nicely, rather than just exiting and forcibly aborting the thread while it's in the middle of doing something.
Both of those links that you provide have the correct answer- BackgroundWorkers will be closed when the program is closed. Unmanaged resources are the ones you have to worry about explicitly closing.
K I am looking at a primarily single thread windows forms application in 3.0. Recently my boss had a progress dialogue added on a separate thread so the user would see some activity when the main thread went away and did some heavy duty work and locked out the GUI.
The above works fine unless the user switches applications or minimizes as the progress form sits top most and will not disappear with the main application. This is not so bad if there are lots of little operations as the event structure of the main form catches up with its events when it gets time so minimized and active flags can be checked and thus the dialog thread can hide or show itself accordingly.
But if a long running sql operation kicks off then no events fire. I have tried intercepting the WndProc command but this also appears queued when a long running sql operation is executing. I have also tried picking up the processes, finding the current app and checking various memory values isiconic and the like inside the progress thread but until the sql operation finishes none of these get updated. Removing the topmost causes the dialog to disappear when another app activates but if the main app is then brought back it does not appear again.
So I need a way to find out if the other thread is minimized or no longer active that does not involve querying the actual thread as that locks until the sql operation finishes.
Now I know that this is not the best way to write this and it would be better to have all the heavy processing on separate threads leaving the GUI free but as this is a huge ancient legacy app the time to re-write in that fashion will not be provided so I have to work with what I have got.
Any help is appreciated
It sounds as if the long running operation is bound to the progress dialog? That's usually a bad idea and I wonder whether the progress can be showed at all.
However you should consider using a BackgroundWorker for your long running operations. So your GUI (the main form as well as the progress dialog stays alive).
This way you should be able to send the minimize event of the main form to the progress dialog which can react to it instantly.
Btw. the BackgroundWorker supports progress reports on its own.