У меня сейчас есть форма с TabControl
, содержащая некоторые TabPage
с. Каждый TabPage
имеет несколько элементов управления с логикой проверки и соответствующими ErrorProvider
с. На моем OK_Button_Clicked
событии я звоню Form.ValidateChildren()
, чтобы определить, сохранить ли и закрыть форму. Теперь предположим, что у меня есть элемент управления на вкладке 1, который не проходит проверку, но в настоящее время видимой вкладкой является вкладка 2. Когда пользователь нажимает кнопку ОК, он не получает визуальной индикации о том, почему форма не закрывается. Я хотел бы иметь возможность автоматически переключаться на вкладку, где проверка не удалась, чтобы пользователь мог видеть сообщение об ошибке ErrorProvider
.
Один из подходов состоит в том, чтобы подписаться на события Validated
и validating
всех соответствующих элементов управления и знать, в какой вкладке находится каждый из них, и при каждом сбое проверки может быть создан список вкладок, которые не прошли проверку. Поскольку, насколько я знаю, событие ValidationFailed
не генерируется, это может быть громоздким (например, определение логического значения для каждого элемента управления, установка его в значение false перед проверкой и значение true в его событии Validated
). И даже если бы у меня было такое событие, я был бы вынужден прослушать много событий проверки, по одному для каждого элемента управления, которые могут не пройти проверку, и поддерживать список неподтвержденных вкладок в коде. Здесь следует отметить, что прямая подписка на события проверки TabPage
не работает, поскольку они проходят проверку, даже если содержащиеся в них элементы управления не проходят проверку.
Другой подход может использовать тот факт, что элементы управления в моем TabPage
оказались пользовательскими элементами управления. Затем я мог бы заставить их реализовать интерфейс, такой как:
interface ILastValidationInfoProvider
{
public bool LastValidationSuccessful {get; set;}
}
Например:
public MyControl : UserControl, ILastValidationInfoProvider
{
MyControl_Validing(object sender, object sender, CancelEventArgs e)
{
if (this.PassesValidation())
this.ErrorProvider.SetError(sender, null);
LastValidationSuccessful = true;
else
e.Cancel = true;
this.ErrorProvider.SetError("Validation failed!", null);
LastValidationSuccessful = false;
}
}
А потом, после звонка на ValidateChildren
я мог бы использовать такой код:
public void OK_Button_Click
{
if (form.ValidateChildren())
this.Close()
else
foreach (TabPage tab in this.TabControl)
foreach (Control control in tab.Controls)
{
ValidationInfo = control as ILastValidationInfoProvider
if (ValidationInfo != null && !ValidationInfo.LastValidationSuccessful)
{
this.TabControl.SelectTab(tab);
return;
}
}
}
Мне больше нравится этот подход, но он не учитывает случаи, когда проверяемые элементы управления не являются пользовательскими.
Я бы с удовольствием использовал лучший подход. Есть идеи?
РЕДАКТИРОВАТЬ Я использую Form.AutoValidate = EnableAllowFocusChange
(как рекомендовано Крисом Селлсом в его книге WinForms), поэтому фокус действительно может измениться с элементов управления, которые не прошли проверку (включая перемещение на другие вкладки). Я также обновил пример кода для пользовательского элемента управления, чтобы подчеркнуть тот факт, что ErrorProvider
находится внутри него.