Я пишу приложение для Windows, которое в основном работает в фоновом режиме со значком уведомления для взаимодействия с ним. Значок уведомления может выполнять основные действия, такие как выход из приложения или отображение информации о нем. Он также может запустить диалоговое окно модальной конфигурации.
Код, который создает диалог, довольно прост:
using(var frmSettings = new SettingsForm(configuration))
{
frmSettings.ConfigurationChanged += ConfigurationChangedHandler;
frmSettings.UnhandledException += UnhandledExceptionHandler;
frmSettings.ShowDialog();
}
Класс SettingsForm
в основном имеет три элемента управления GroupBox
, с элементами управления Label
и TextBox
в каждом и 4 Button
элементами управления внизу: "Advanced..."
, "Restore Defaults"
, "Cancel"
и "Apply"
. Каждый TextBox
имеет обработчик событий Validating
, подключенный через конструктор. Каждая кнопка имеет обработчик Click
, подключенный через конструктор. Каждый из них делает довольно очевидные вещи: открывает другое модальное диалоговое окно с более расширенными настройками, восстанавливает текстовые поля к их значениям по умолчанию, закрывает диалоговое окно или сохраняет изменения, запускает событие ConfigurationChanged
и , затем закрывает диалоговое окно (но только если все поля действительны!).
В случае ошибки ввода формы я отменяю соответствующее событие Validating
, устанавливая ((CancelEventArgs)e).Cancel = true
. Однако поведение обеих форм по умолчанию состояло в том, что пользователь не мог изменить фокус при сбое проверки. Я нашел это довольно раздражающим и в конечном итоге нашел в конструкторе возможность автоматически проверять, когда пользователь покидает поле, но разрешать ему уходить, даже если проверка не удалась: AutoValidate = EnableAllowFocusChange
. [1]
Моя "Apply"
кнопка Click
Обработчик выглядит в основном так:
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));
}
}
В настоящее время я тестирую код, разбивая первую строку и построчно шагая по методу. По сути, ValidateChildren
возвращает false, как и ожидалось, и весь блок if
, включая this.Close()
, пропускается. Тем не менее, если я перейду весь путь к основанию метода, а затем выйду из него, я снова окажусь на линии frmSettingsForm.ShowDialog()
, и форма магически закроется.
Кнопка "Apply"
устанавливается как AcceptButton
формы. Интересно, неявно ли подключен обработчик к событию кнопки Click
, чтобы автоматически закрывать форму при нажатии кнопки. Это не должно звучать логично, особенно если учесть, что нет способа отменить событие Click
, но это единственное объяснение, которое я могу придумать. Чтобы проверить эту теорию, я попытался сбросить AcceptButton
в конструкторе, но моя форма все еще закрывается, когда данные неверны.
Что закрывает мою форму и как мне ее остановить?
[1]: Если кому-то еще не удается найти его, это свойство формы, а не свойство каждого отдельного элемента управления (как я и ожидал).