Can I put commands after Form.Close()? - c#

In C#,
Suppose I am in a form, and I pressed a button I made to close it.
this.Close();
some_action(); //can I do this??
can I perform another action after I closed the form or does the thread die and everything after that is lost?

Depends on what you are trying to do and the context of the statement. If the form being closed is the main form which owns the message loop, you can't do any UI related stuff (e.g. you can't display another MessageBox). If you are not doing it from another window (which doesn't own the message loop), you could do anything (even UI related) as long as you aren't manipulating the closed form object (you'll get ObjectDisposedException just like any disposed object).
By the way, the thread doesn't die as a result of Close. Closing the main window causes the message loop to terminate and not the thread itself. For example, the following program
static void Main() {
Application.Run(new Form1());
Application.Run(new Form2());
}
will display Form2 after Form1 is closed (using a newly created message loop). This proves that the thread is not dead.

If you try to manipulate the form or any of it's controls after calling Close you're going to run into trouble. However there's nothing preventing you from calling some other method - for instance a logging method - after calling Close.

Handle FormClosing Event and do additional action in event handler.

Related

How to ensure Form is completely closed and removed from display before continuing?

I have tried what I saw in this post, which did not answer my question. See my code and further explanation below.
// In MyForm : Form
private void SetupForImportantTask()
{
// Does a ton of stuff to set up for ImportantTask, then...
this.Close();
}
private void MyForm_FormClosed(object sender, FormClosedEventArgs e)
{
// otherForm is an instance of OtherForm : Form
otherForm.ImportantTask(variousData);
}
// In OtherForm class...
public void ImportantTask(object variousData) {
// Does a bunch of stuff that takes a long time
// Provides UI feedback to notify the user a process in under way
}
Explanation: As you can see in the code, the idea is to do a bunch of setup for ImportantTask in MyForm, then call back into OtherForm with the setup information established after MyForm has already closed.
What I am seeing instead:
Even though I am not calling ImportantTask until the Closed event on MyForm has already fired, meaning semantically that the Form is already closed, MyForm remains open while the UI thread hangs, until ImportantTask is complete. The UI notification of the long-running process is never displayed, and MyForm only closes after ImportantTask is complete.
If MyForm is not closed when the Closed event fires, how else can I determine that the Form is actually closed and cleared from the screen?
Or:
What silly thing have I missed?
To answer your question, a form will disappear from screen after Form_Closed event has fired, therefore after calling each method that has registered to that event. The Dispose() method is called right after firing the event (from ReferenceSource, check the end of this method).
If you want to make sure a form has disappeared, you have the IsHandleCreated property, which tells you if there is a handle associated with the form (from MSDN).
About application design, a Form should be doing only what is has been designed for : display graphical elements and handling user input.
User Input should be filtered and your form should be firing events that a controller class would catch and manage on another thread.
When controller is done with user input, it should tell the form that it is OK to refresh the display.
Your design as it is now is broken, if you call from a Form a method of another Form, until that method returns you are still inside the calling method of the first Form.
In other words, method A does not finish until method B ( called by method A ) returns the control flow to its caller.
There are various ways you can properly do this, you can simply hide your first form changing its visibility instead of closing it, or you can run the importanttask method on other form async, or you can even simply post a message to second form and terminate yoiur first form then second form will respond to that message.
of course, pay attention at objects life cycle as well and in the end the method you decide to use depends on the rest of the application and on your taste.

How can I determine if my Forms window is still valid?

I have a window that receives asynchronous events from a worker thread. Sometimes these events come in after the window is closed and when I call Invoke() to process the event, I get an exception.
How can I test to make sure the window is still good. Or to cause all events to be processed somewhere in the closing lifecycle?
thanks - dave
You can check IsHandleCreated before calling invoke, to make sure the form is created and is not destroyed:
if (this.IsHandleCreated)
{
//this.Invoke ...
}
The property returns false if the form handle is still not created or it has destroyed after closing the form. It also prevents the error of calling invoke before showing the form and before the handle is created.
If for any reason you just care about closing the form, you can check IsDisposed property.

Closing Parent without closing child

I have a project where a setup dialog (Parent) pops. When the user hit continue a main dialog is opened (Child).
From within the main dialog the user can re-edit the setup dialog (Parent). When the user clicks on X to close the setup dialog, the application terminates.
I assume this is because we close the Parent and it disposes all its children
Is it possible to close the Parent (or hide it) without closing the main dialog (child)?
If not would the following fix would work?
Open the Main Dialog as Parent and make it open the setup dialog (Child)
In the Program.cs file, you probably have a function like this:
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
This function is the entry point for your application. The Application.Run() function runs the main loop of the application. The main loop of a graphical application is the place where the event handler triggers the events, the UI gets updated and so on. If an event (for example pressing a button) takes too long to process, the UI hangs. To prevent this from happening, one can use threading.
The Application.Run() function is overloaded, so if the function has a parameter (new Form1() in this case), the form becomes the 'main' form, so the main loop will exit when the form is closed.
To fix this issue, you need to remove the parameter, which will make the main loop run without closing when the form closes:
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run();
}
However, this creates 2 problems:
No form is displayed at start-up, because we removed that from the Main function. To fix this, you need to create a new form in the main function, and show it:
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form1 form = new Form1();
form.Show();
Application.Run();
}
The application will not exit when you close the form. If you close all forms, the process will be still running, so you need to call Application.Exit(); when you want the application to exit (e.g. form closing event).
Or, you just cannot understand that a modal window cannot live without a parent. When the parent is minimized, all the modal forms became hidden. When the parent is closed, the same is happening to the modal forms.
So it is a bad practice to trick the model form to stay alive after the parent dies. Just try to stay the pattern in which your second form is just another same equal form as the first one.

How to set a windows form as the main form of the application? C#

I'm using Visual Studio C# and I got stuck in making a new form become the main one. I need the application to be closed when it get closed and I want to close the previous form without closing the application.
Current attempt (won't work):
FormClass newForm = new FormClass();
newForm.Show()
previousForm.Close()
First understand why the Application is exiting. From the documentation of Application.Run(Form):
This method adds an event handler to
the mainForm parameter for the Closed
event. The event handler calls
ExitThread to clean up the
application.
If you can get away with just hiding it rather than closing it
FormClass newForm = new FormClass();
newForm.Show();
previousForm.Hide();
If you need to close it (or would rather)
Alter Program.cs. To prevent the event handler added by Run(Form) from terminating you, use an overload of Run() that doesn't add such a handler:
var form = new Form1();
form.Show();
Application.Run(); // The application will not exit when form is closed
But in this case, you will need to call Application.Exit() yourself when the newForm is closed (or under any other circumstances in which you want to Exit).
If your intent is to use something like a splashscreen, try call the first form on a background thread, them abort the thread after the task if completed. The "first" form will be closed.
Or, just close the "splashscreen form", ending the background thread.
It helps?

Are events guaranteed to go off?

Let's say I have a form SomeForm that inherits from Form.
public class SomeForm : Form
{
private void SomeForm_FormClosed(object sender, FormClosedEventArgs e)
{
MessageBox.Show("FormClosed event in SomeForm class");
}
}
public class Consumer
{
SomeForm someForm = new SomeForm();
someForm = null; //Ideally the messagebox would display here
SomeForm someForm = new SomeForm();
someForm.Close(); //Messagebox would display in this case as well
}
I want to show that MessageBox whenever the form is closed. Should I stick that in the FormClosed event? Is it safe to assume that the FormClosed event will fire every time something like the destructor is run? Is there a better place to put this code that must occur when the form is closed?
EDIT
Someone made a good point in the comments below. It seems the event does not fire when the instance of the class is set to null. However, will the destructor or some other method still be called when the instance is set to null. I want to guarantee that my code runs when the user is finished with the class.
I'm also aware that forcibly shutting down the system, ending the process, acts of God, etc will not cause my code to run no matter what. =)
Yes, it will be called unless something exceptionably happens, like killing it via system commands or pulling the plug. Other cases include
setting the variable to null (not calling the Close method)
Exception in another delegate: All events are MulticastDelegates, and the delegates are executed in order of appearence in that MulticastDelegate, if one of the previous delegates before yours causes an exception, your delegate will not be called.
It will get called unless your executable is forcibly closed (via task manager or taskkill from the command line) or the program crashes.
EDIT: I did some experimentation and found the following:
If you set your reference to the form to null, the form remains visible, and when the form is closed, the event gets raised.
If your form is a child form and the main form gets closed, the child form closes WITHOUT the event being raised.
If you call the form's Hide() method, the event does NOT get raised. Subsequently closing the main form, as mentioned above, will not cause the event to get raised.
Overriding OnClosed() will not help because it's still not called if the main form is closed.
Calling the form's Dispose() method (which is what the GC would eventually do if nothings pointing at it) will also not cause the event to get raised.
It looks like there really isn't a way to GUARANTEE the code will get called from within the form. You can put the code after the Application.Run(); in your Main() and it will get called there. There's also an event for Application.ApplicationExit that would get called unless you have exceptional circumstances (forcibly closed or crash).
You can register a handler for the Application.ApplicationExit event in your form, but be aware that by this time, your object has already been disposed, so you can't do anything with it.
FormClosed event is raised by OnClosed method. So if you want certain level of guarantee, you can override OnClosed method.

Categories

Resources