代码之家  ›  专栏  ›  技术社区  ›  Ohad Schneider

WinForms TabControl验证:切换到验证失败的选项卡

  •  3
  • Ohad Schneider  · 技术社区  · 14 年前

    我现在有一个表单 TabControl 包含一些 TabPage 每一个 制表 具有多个具有验证逻辑和适当的控件 ErrorProvider 在我的 OK_Button_Clicked 事件,我呼叫 Form.ValidateChildren() 以确定是否保存和关闭窗体。现在,假设我在选项卡1中有一个未通过验证的控件,但当前可见的选项卡是选项卡2。当用户按“确定”时,他将看不到窗体未关闭的原因。我希望能够自动切换到验证失败的选项卡,以便用户可以看到 错误提供程序 错误的指示。

    一种方法是订阅 Validated validating 所有适当控件的事件,以及知道每个控件都在哪个选项卡中,每当验证失败时,都可以构建验证失败的选项卡列表。因为没有 ValidationFailed 据我所知,事件是生成的,这可能很麻烦(例如,为每个控件定义一个布尔值,在验证前将其设置为false,在其上设置为true 验证的 事件)。即使我有这样一个事件,我也会被迫监听许多验证事件,每一个可能验证失败的控件一个,并在代码中维护未验证选项卡的列表。我要注意的是,直接订阅 制表 的验证事件不起作用,因为它们通过验证,即使其中包含的控件未通过验证。

    另一种方法可以利用这样一个事实,即 制表 恰好是自定义控件。然后我可以让它们实现一个接口,比如:

    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在其WinForms手册中推荐的那样),因此焦点确实可以从未通过验证的控件(包括移动到其他选项卡)更改。我还更新了自定义控件的示例代码,以强调 错误提供程序 位于内部。

    1 回复  |  直到 12 年前
        1
  •  3
  •   nalply Gagan    12 年前

    好吧,我终于明白了。

    我有一本字典,它的键是 TabPages 价值观是 HashSet 对应选项卡中未验证的控件。这很容易通过订阅每个选项卡中控件的所有验证和验证事件来完成。最后,在 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;
            }
        }
    

    我觉得很甜!