WinForms TabControl 验证:切换到验证失败的选项卡
我目前有一个带有 TabControl
的表单,其中包含一些 TabPage
。每个 TabPage
都有几个带有验证逻辑和适当的 ErrorProvider
的控件。在我的 OK_Button_Clicked
事件中,我调用 Form.ValidateChildren()
以确定是否保存并关闭表单。现在,假设选项卡 1 中有一个控件验证失败,但当前可见的选项卡是选项卡 2。当用户按下“确定”时,他不会得到任何关于表单未关闭原因的视觉指示。我希望能够自动切换到验证失败的选项卡,以便用户能够看到 ErrorProvider
的错误指示。
一种方法是订阅所有适当控件的 Validated
和 validating
事件,并了解每个控件位于哪个选项卡中,每当验证失败时,就会显示一个选项卡列表可以构建失败的验证。据我所知,由于没有生成 ValidationFailed 事件,这可能很麻烦(例如为每个控件定义一个布尔值,在验证之前将其设置为 false 并在其 Validated 上设置为 true > 事件)。即使我有这样的事件,我也将被迫监听许多验证事件,每个验证事件可能会失败,并在代码中维护未验证选项卡的列表。我应该在这里指出,直接订阅 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
(正如 Chris Sells 在他的 WinForms 书中所推荐的那样),因此焦点确实可以从验证失败的控件更改(包括移动到其他选项卡)。我还更新了自定义控件的示例代码,以强调 ErrorProvider
驻留在其中的内部事实。
I currently have a Form with a TabControl
containing some TabPage
s. Each TabPage
has several controls with validation logic and appropriate ErrorProvider
s. On my OK_Button_Clicked
event, I call Form.ValidateChildren()
in order to determine whether to save and close the form . Now, suppose I have a control in tab 1 that fails validation, but the currently visible tab is tab 2. When the user presses OK, he would get no visual indication as to why the form is not closing. I would like to be able to automatically switch to a tab where validation failed, so the user would see the ErrorProvider
's indication of error.
One approach would be subscribing to the Validated
and validating
events of all appropriate controls, and knowing which tab each of them is in, whenever one fails validation, a list of tabs that failed validation could be built. Since no ValidationFailed
event is generated as far as I know, this could be cumbersome (e.g. defining a boolean for each control, setting it to false before validation and to true on its Validated
event). And even if I had such an event, I would be forced to listen to many validation events, one for each control that might fail validation, and maintain the list of unvalidated tabs in code. I should note here that subscribing directly to the TabPage
's validation events doesn't work, because they pass as validated even if controls contained inside them fail validation.
Another approach could leverage the fact that the controls in my TabPage
happen to be custom controls. I could then make them implement an interface such as:
interface ILastValidationInfoProvider
{
public bool LastValidationSuccessful {get; set;}
}
For example:
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;
}
}
And then, after the call to ValidateChildren
I could use code such as:
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;
}
}
}
I like this approach better but it doesn't cater to cases where the controls being validated are not custom.
I would gladly use a better approach. Any ideas?
EDIT I am using Form.AutoValidate = EnableAllowFocusChange
(as recommended by Chris Sells in his WinForms book), So the focus can indeed change from controls that failed validation (including moving to other tabs). I have also updated the sample code for the custom control to emphasize the fact that the ErrorProvider
resides internally inside it.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
好吧,我终于明白了。
我保留了一个字典,其键是 TabPages ,值是相应选项卡中未经验证的控件的 HashSet 。通过订阅每个选项卡中控件的所有验证和验证事件可以轻松完成此操作。最后,在
OK_BUtton_Click
中,如果ValidateChildren
失败,我知道其中一个哈希集将不为空,我只需跳转到第一个未验证的选项卡(仅当当前选定的选项卡不存在时)本身没有任何错误)。我觉得还蛮甜的!
OK so I finally figured it out.
I keep a dictionary whose keys are the
TabPages
and the values areHashSet
s of unvalidated controls within the corresponding tab. This is easily done by subscribing to all the validating and validated events of the controls in each tab. Finally, inOK_BUtton_Click
, ifValidateChildren
fails, I know one of the hashsets will be none empty and I simply jump to the first unvalidated tab (only if the currently selected tab doesn't have any error itself).I think it's pretty sweet !