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.
Related
I am pretty new to C# and have a problem with a Windows Form project. I am
not sure if I am doing this correctly?
I have a 'Help button' on a windows form which shows a 'Modeless dialog box'.
I want this to be Modeless so the user can carry on working in the main form
and leave open the Help form and if required minimise it.
I am requiring the user to be able to press the 'Help button' again which will
simply bring the Modeless dialog box back to the front even if it is minimized.
I do not want to create a new 'Modeless Help dialog box' and end up with many
of them I just want the single one.
I have a global variable for the main form
FormHelp goHelpDialog = null;
and the handler for the 'Help button' is
private void buttonHelp_Click(object sender, EventArgs e)
{
// If we havent already created a HelpDialog create it and Show() it
// Else just bring it to the front
if (goHelpDialog == null)
{
goHelpDialog = new FormHelp();
// Show goHelpDialog as a modless dialog so dont dispose of a modeless as we want that to stay alive
// Note Dispose() is automatically called when user closes dialog.
goHelpDialog.Show();
}
else
{
if (goHelpDialog.WindowState == FormWindowState.Minimized)
goHelpDialog.WindowState = FormWindowState.Normal;
goHelpDialog.BringToFront();
}
return;
}
This works fine if the user keeps hitting the 'Help button'. The problem I have is when
the user closes the 'Modeless Help dialog box' and presses the 'Help button' again I
get an assertion because
if (goHelpDialog == null)
is not null. Therefore a new 'Modeless Help dialog box' is not created.
I assume that goHelpDialog is not being Dispose() correctly?
Your advice is appreciated thank you.
I've built a Windows form application which contains some forms. I would like to create a button on a certain form which saves its state.
For example, if I have a textbox in which a user typed "Hello" and pressed the save button, when he goes back to this form, the textbox would still say "Hello". I want it to happen only in the same execution of the program, which means when the program closes and reopens, the textbox wouldn't say "Hello" anymore (which is why Settings don't fit my need I believe, because they keep the changes between executions).
Since you only want the form to retain its state while the application is running, the solution is very simple: never close the form, just hide it. When you're ready to display it again, show it. It will re-appear on the screen, everything exactly as it was left. (Unless, of course, you loop through the controls and reset their properties.)
In the simplest case, you accomplish this by substituting calls to this.Close with this.Hide. But it is likely more complicated than that, since the user can close your form with the big red X. To ensure all attempts to close the form are stealthily rerouted as requests to hide the form requires some minor finesse:
private void MyForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
e.Cancel = true; // cancel the request to close
this.Hide(); // hide the form instead
}
}
Note that this code checks the close reason and ensures that it's a user-initiated close request. This is very important. If you omit this part, you can't close the form programmatically, either!
Store your data in static variables and they will live until you close your program.
static string textboxText = textbox1.text;
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.
This is the code in question:
private void FormAccounting_FormClosing(object sender, FormClosingEventArgs e)
{
Properties.Settings.Default.FormAccountingLocation = this.Location;
Properties.Settings.Default.Save();
if (IsEditing)
{
MessageBox.Show("Please save or cancel open transactions before closing the accounting window.", "Open Transactions", MessageBoxButtons.OK, MessageBoxIcon.Information);
e.Cancel = true;
}
}
I've added breakpoints to the e.Cancel = true; line to ensure it's being executed.
The form closes immediately after clicking Ok.
Here's the code that calls FormAccounting:
private void buttonAccounts_Click(object sender, EventArgs e)
{
FormAccounting NewFormAccounting = new FormAccounting();
NewFormAccounting.Show();
}
Canceling the form close event works to prevent:
User closing the form
Application.Exit from exiting the application
Code from calling Form.Close on the form
But it does not work to prevent:
User closing application's main form
Code calling Form.Dispose on the form
Code calling Form.Close on the application's main window
The last 3 cases don't even trigger the form close event on the non-main form, so the form goes away without a chance to cancel it. Perhaps your application is causing the form to first close in one of the first 3 ways, which triggers the event, and then in one of the second 3 ways (or something similar), which does not trigger the event and forces the form closed anyway.
Edit:
Add this function to your form's code and it will allow you to review in the debugger what the call stack looks like when your window is getting closed so you can see what is actually causing it:
protected override void DestroyHandle()
{
System.Diagnostics.Debugger.Break();
base.DestroyHandle();
}
I'm writing a Windows application that basically runs in the background with a notification icon to interact with it. The notification icon can do basic things like exit the application or show information about it. It can also launch a modal configuration dialog.
The code that creates the dialog is pretty straightforward:
using(var frmSettings = new SettingsForm(configuration))
{
frmSettings.ConfigurationChanged += ConfigurationChangedHandler;
frmSettings.UnhandledException += UnhandledExceptionHandler;
frmSettings.ShowDialog();
}
The SettingsForm class basically has three GroupBox controls, with a Label and TextBox control in each, and 4 Button controls at the bottom: "Advanced...", "Restore Defaults", "Cancel", and "Apply". Each TextBox has a Validating event handler wired up through the designer. Each button has a Click handler wired up through the designer. Each of them does pretty obvious things: opens another modal dialog with more advanced settings, restores the textboxes to their default values, closes the dialog, or saves the changes, fires the ConfigurationChanged event, and then closes the dialog (but only if all fields are valid!).
When there is a form entry error I cancel the corresponding Validating event by setting ((CancelEventArgs)e).Cancel = true. However, the default behavior of both forms was to prevent the user from changing focus when validation failed. I found this pretty annoying and eventually found the option in the designer to still automatically validate when the user leaves the field, but to allow them to leave even if validation fails: AutoValidate = EnableAllowFocusChange.[1]
My "Apply" button Click handler looks basically like this:
private void btnApply_Click(object sender, EventArgs e)
{
try
{
if(this.ValidateChildren())
{
this.Configuration.Field1 = this.txtField1.Text;
this.Configuration.Field2 = this.txtField2.Text;
this.Configuration.Field3 = this.txtField3.Text;
if(this.Configuration.Changed)
{
this.Configuration.Save();
this.OnConfigurationChanged(new ConfigurationChangedEventArgs(
this.Configuration));
}
this.Close();
}
}
catch(Exception ex)
{
this.OnUnhandledException(new UnhandledExceptionEventArgs(
"Failed To Apply Configuration Settings",
ex));
}
}
I'm currently testing out the code by breaking on the first line and stepping through the method line by line. Essentially, ValidateChildren is returning false as expected and the entire if block, including the this.Close() are skipped. Yet, if I step all the way to the bottom of the method and then step out of it I end up back on the frmSettingsForm.ShowDialog() line and the form is magically closed.
The "Apply" button is set as the form's AcceptButton. I wonder if it's implicitly attached a handler to the button's Click event to automatically close the form when the button is pressed. That doesn't sound like it logically should be assumed, especially considering there doesn't seem to be a way to cancel the Click event, but it's the only explanation that I can come up with. To test that theory, I have tried unsetting the AcceptButton in the designer, but my form still closes when the data is invalid.
What is closing my form and how do I stop it?
[1]: If anybody else has trouble finding it, it's a form property, not a property of each individual control (as I expected it would be).
Do you have the DialogResult of the Button set? If so, when you click the Button, the DialogResult of the Form will be set to that value and the modal Form will close. To prevent this, when validation fails in your Click handler, set the Form's DialogResult to DialogResult.None.
I don't know why that happens, but you could override the event OnFormClosing and check for the value of DialogResult according to your logic.
If (DialogResult != Windows.Forms.DialogResult.Cancel )
e.Cancel = True