Why Form.Close wait MessageBox.Show? - c#

look this please:
var form = new Form();
form.Shown += (_, __) =>
{
var timer = new System.Windows.Forms.Timer { Interval = 1000 };
timer.Tick += (x, xx) =>
{
timer.Stop();
GC.KeepAlive(timer);
timer.Dispose();
form.Close();
Application.DoEvents(); // no effect
// it will cause form keep show
MessageBox.Show("asdf");
// but if this, that's fine
// BeginInvoke(new Action(() => MessageBox.Show("asdf")));
};
timer.Start();
};
form.ShowDialog();
form.Close before MessageBox.Show, but form will not close until close msgBox, please help.
--end--
all in code, why need more words? all in code, why need more words? all in code, why need more words?

When you show a form as modal using ShowDialog(), calling Close in fact sends a WM_CLOSE message and then it sets DialogResult to Cancel which acts as a flag for modal message loop to exit the loop.
So Close will not close or hide the modal dialog immediately. Then after finishing the modal message loop, the modal dialog will be hide (but not destroyed).
MessageBox method also blocks the execution of code, so codes after the message box will execute just after closing the message box. So now it's clear why after calling Close, first the MessageBox shows then after closing message box, form closes.
Just to make it easier to understand, here is a pseudo-code which shows what is happening when you call ShowDialog in your code:
Form Shows
While Form.DialogResult != None
{
Form.Close → Sends WM_CLOSE → Sets Form.DialogResult = Cancel
MessageBox.Show and wait until MessageBox closes
}
Form Hides
Just keep in mind, Close is not equal to return, it means the code which you have after Close will run as well. Here the code is MessageBox which blocks the loop until after MessageBox closes.
To hide the dialog immediately, replace the form.Close() with form.Hide(), this way without waiting for the loop, you are commanding the form to get hidden. But it doesn't mean the form has been closed and therefore lines of code which you have after ShowDialog will not run until after the loop finishes.
For more information about how Close and ShowDialog work, you may want to take a look at a Windows Forms source code, specially the following lines:
LocalModalMessageLoop in Application
CheckCloseDialog in Form
WMClose in Form

Related

Show modal loading window in Winforms for long-running process

I would like to show a wait gif, while verifying a file and this is what I have tried so far.
There is a form - Form1, where user clicks a button to verify a file, and there is another form - Wait, with just a picturebox showing a gif image.
button_click()
{
Wait wait = new Wait();
wait.ShowDialog();
VerifyFile();
wait.Close();
}
The Wait form does show up, but it doesn't close. Also, the verification is also not done. It continues only when I manually close the Wait form.
How to auto close the wait form, once VerifyFile() is complete.
The problem with your code is that Form.ShowDialog() method is synchronous and it waits for the result from the "Form" dialog. This means that the code execution is hold up untill the "wait" dialog will be closed.
Consider moving the VerifyFile() method into Wait dialog:
class Wait: Form
{
public Wait() : base()
{
System.Threading.Tasks.Task.Factory.StartNew(() => VerifyFile());
}
}
You can close this dialog when after VerifyFile execute's over.

WinForm closes even after removing Close()

I'm encountering strange behaviour from my WinForms app in VS 2010. I launch a new form using straight-forward code:
MainDisplayForm.cs:
using (MyForm myForm = new MyForm())
{
var result = myForm.ShowDialog();
if (result == DialogResult.OK)
{
// do stuff
}
}
I added a Cancel button to MyForm that displayed a confirmation MessageBox to the user and then called this.Close(). I later removed the this.Close() line because I added a dedicated Close button. However, whenever I press Cancel the instance of MyForm still closes!
MyForm.cs:
private void cmdCancel_Click(object sender, EventArgs e)
{
DialogResult result = MessageBox.Show( ... )
// clear the form if user really wants to quit
// this.Close()
// even after removing the above line, program still jumps to FormClosing
}
When I debug line-by-line after clicking on the Cancel button, the program flow just jumps to MyForm_FormClosing after it hits the end of cmdCancel_Click. I created a new button and set its click event to cmdCancel_Click and it did not close the form - so the problem is solved, but I am still wondering if this is just a bug, or something else? I also made sure to reset the DialogResult property of my Cancel button back to None (after changing it to Cancel before I introduced the dedicated Close button).
When exiting the scope of 'using' statement, it calls 'myForm.Dispose()' (that's the whole point of 'using' - to make sure Dispose()is called). This in turn destroys 'myForm' instance, including closing the window.

MessageBox shown before form closes

Why is the messagebox shown before the form closes?
SomeForm myForm = new SomeForm();
myForm.Show();
MessageBox.Show("Some text");
Do I need to start a new thread, and wait for it to finish? I've never come across this problem before.
You need to use Form.ShowDialog() instead. Form.Show shows a modeless window, whereas Form.ShowDialog shows a modal form, i.e., that the user has to close before continuing.
Your example never actually closes myForm...only shows it. I would expect the code above to show myForm and then immediately show the MessageBox.
If you want myForm to close before showing the MessageBox, you'll need to call myForm.Close() at some point.
The reason for this is that myForm.Show(); starts the opening of a new window, however it is not a blocking call. It's not a dialog, it's a separate window, which runs on it's own.
If you want SomeForm to show as a Dialog (blocking window, waits for close to continue execution), then use ShowDialog. If you want to wait till the window is opened before you show the MessageBox, then add the MessageBox to the OnLoaded on the SomeForm claa.
If it's important that the user not be able to interact with the main form while this other form is being shown then you can use myForm.ShowDialog instead of Show. ShowDialog is a blocking function, so it won't return until the other form is closed. Show, on the other hand, just shows the other form and then immediately returns without waiting for the form to be closed.
If it's intentional that the other form is not being shown modally, and you don't (or can't) make that change, then you can use events to show a message box when the other form is closed.
SomeForm myForm = new SomeForm();
myForm.FormClosed += (form, args) =>
{
MessageBox.Show("Some text");
};
myForm.Show();
This will add an event handler, which fires when the other form is closed, and executes the desired code at the appropriate time.

C# form closing at program end

I have a windows forms question:
Program.cs:
Application.Run(new frmStart());
frmStart: on btnLoad_Click,
frmLoad formLoad = new frmLoad();
formLoad.Show();
this.Hide(); // if I do a this.Close(); after it shuts down and doesn't get to show the form
frmLoad: on btnCancel_Click:
Application.Exit();
// or this.Close();
// or even: base.Close();
The form disappears but the program doesn't end, I still have to press the blue "Stop Debugging" to make it stop.
I have been looking... I know it is possible to make the program really stop, and not just freeze when you close the second form, even if you don't keep the first form on the screen, but can't remember and can't figure out how.
Ack, -1 on Application.ExitThread!
The issue is that you haven't closed the main form. The simplest way is to hook onto the 2nd form's Closed event and have it close the main form. For example the code to open the 2nd form changes to:
var newForm = new frmLoad();
newForm.FormClosed += (closedSender, closedE) => Close();
newForm.Show();
Hide();
This essentially sets up so that when the frmLoad form closes, the main form calls it's Close() method. I used a Lambda expression for the event handler, but you can just as easily create a private method accepting an (object sender, EventArgs e) and point .FormClosed at it.
*Edit: Sorry, missed that you only want to close on certain state. In which case on your frmLoad, create a public property such as:
public bool UserCancelled
{
get;
private set;
}
where the Cancel button sets this to True before closing the form. Your event handler in the main form changes to:
var newForm = new frmLoad();
newForm.FormClosed += (closedSender, closedE) =>
{
if (newForm.UserCancelled)
Close();
};
newForm.Show();
Hide();
In frmStart add:
public static frmStart Current;
Then in the constructor add:
Current = this;
Then in frmLoad: on btnCancel_Click:
frmStart.Current.Close();
You really should call Close() on both. That's the only clean way as otherwise the first form never is told to close down and doesn't clean up.
You may know that it's safe to do this, but someone else working on the code later may add code in the OnClose in the first form that they need called. They will say not nice things about you when they finally figure out why their code is not called.
If you close both, then your app will exit.
Please use the Application.ExitThread() method, the method exits the message loop on the current thread and closes all windows on the thread.
http://msdn.microsoft.com/en-us/library/system.windows.forms.application.exitthread
I vote yuck on all the answers. Override Form Closing in your primary form and close the secondary form first.

C#/.NET: how do I close the application from a parent window?

I have a Windows application that has 2 Forms. From one form I am opening a 2nd form.
When opening the 2nd form I am hiding 1 form and in the second foem I am starting a thread.
Now I want to close the application.
But I was not able to do that.
On my 1st form I have tried:
Form1 frm = new Form1(this, tcpClient);
frm.ShowDialog();
this.Close();
Application.Exit();
But the application is not ending. It still running.
Any idea how to stop that?
EDIT (CODE Included):
On 1st form's button click event:
this.Hide();
Form1 frm = new Form1(this, tcpClient, serverMsg);
frm.Show();
On 1st form's button FormClosed event:
MessageBox.Show("Before");
Application.Exit();
On 2nd form's load event I am calling a method startThread(); on this method
ilThread = new Thread(incomingListener);
ilThread.IsBackground = true;
ilThread.Start();
When you do frm.ShowDialog() you're opening a modal window. The code will stop at that point until you specify a DialogResult on frm. I.e. frm.DialogResult = DialogResult.Ok;.
If you use frm.Show() that might work for you.
Edit- See #GenericTypeTea's answer first. If after doing that you are still having issues see mine:
From what you describe it sounds like you have left the thread running. Have you tried creating the thread as a background thread or making sure you end that thread in a clean way?
You probably didn't set the Thread you started as a background thread. Background threads are stopped automatically when application closes. Foreground threads will keep it alive.
To set thread as background thread use IsBackground property.
See Thread.IsBackground.
Otherwise you should take care yourself of stopping the started thread before exiting the application.

Categories

Resources