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).