3

我目前有一个TabControl包含一些TabPages 的表单。每个TabPage都有几个带有验证逻辑和适当ErrorProviders 的控件。在我的OK_Button_Clicked活动中,我打电话Form.ValidateChildren()以确定是否保存和关闭表单。现在,假设我在选项卡 1 中有一个未通过验证的控件,但当前可见的选项卡是选项卡 2。当用户按 OK 时,他不会得到关于表单未关闭原因的视觉指示。我希望能够自动切换到验证失败的选项卡,这样用户就会看到ErrorProvider' 的错误指示。

一种方法是订阅所有适当控件的Validatedvalidating事件,并知道每个控件在哪个选项卡中,每当验证失败时,可以构建验证失败的选项卡列表。由于ValidationFailed据我所知没有生成任何事件,这可能很麻烦(例如,为每个控件定义一个布尔值,在验证之前将其设置为 false 并将其Validated事件设置为 true)。即使我有这样的事件,我也将被迫侦听许多验证事件,每个控件可能验证失败,并在代码中维护未验证选项卡的列表。我应该在这里指出,直接订阅TabPage's 的验证事件是行不通的,因为即使其中包含的控件验证失败,它们也会作为验证通过。

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内部驻留的事实。

4

1 回答 1

3

好的,所以我终于想通了。

我保留了一个字典,其键是 the TabPages,值是HashSet相应选项卡中未验证控件的 s 。这很容易通过订阅每个选项卡中控件的所有验证和验证事件来完成。最后,OK_BUtton_Click如果ValidateChildren失败,我知道其中一个哈希集将不为空,我只需跳转到第一个未验证的选项卡(仅当当前选择的选项卡本身没有任何错误时)。

    Dictionary<TabPage, HashSet<Control>> _tabControls 
                           = new Dictionary<TabPage, HashSet<Control>>();

    public OptionsForm()
    {   
        InitializeComponent();
        RegisterToValidationEvents();
    }

    private void RegisterToValidationEvents()
    {
        foreach (TabPage tab in this.OptionTabs.TabPages)
        {
            var tabControlList = new HashSet<Control>();
            _tabControls[tab] = tabControlList;
            foreach (Control control in tab.Controls)
            {
                var capturedControl = control; //this is necessary
                control.Validating += (sender, e) =>
                    tabControlList.Add(capturedControl);
                control.Validated += (sender, e) =>
                    tabControlList.Remove(capturedControl);
            }
        }
    }

    private void Ok_Button_Click(object sender, EventArgs e)
    {
        if (this.ValidateChildren())
        {
            _settings.Save();
            this.Close();
        }
        else
        {
            var unvalidatedTabs = _tabControls.Where(kvp => kvp.Value.Count != 0)
                                              .Select(kvp => kvp.Key);
            TabPage firstUnvalidated = unvalidatedTabs.FirstOrDefault();
            if (firstUnvalidated != null && 
                !unvalidatedTabs.Contains(OptionTabs.SelectedTab))
                    OptionTabs.SelectedTab = firstUnvalidated;
        }
    }

我觉得挺甜的!

于 2010-02-17T23:19:28.703 回答