Check WinForms TabControl: go to the tab where the check failed.

I currently have a form c TabControlcontaining some TabPages. Each TabPagehas several controls with validation logic and corresponding ErrorProviders. In my OK_Button_Clickedevent, I call Form.ValidateChildren()to determine whether to save or close the form. Now suppose I have a control on tab 1 that does not check, but the currently visible tab is tab 2. When the user clicks β€œOK”, he will not receive a visual indication as to why the form does not close. I would like to be able to automatically switch to the tab where the check failed, so the user will see an error message ErrorProvider.

One approach is to subscribe to events Validatedand validatingall the relevant controls and know each tab of each of them; whenever someone refuses to check, a list of tabs that failed to check can be created. Since the event is ValidationFailednot generated, as far as I know, this can be cumbersome (for example, determining the logical for each control, setting it before a lie before checking, and the truth in the event Validated). And even if I had such an event, I would have to listen to many validation events, one for each control that might not perform the validation, and keep a list of unapproved tabs in the code. Here I should note that subscribing to verification eventsTabPage does not work because they pass the test, even if the controls contained within them do not confirm the test.

In another approach, you can use the fact that the controls in my TabPageare custom controls. Then I could implement their interface, for example:

interface ILastValidationInfoProvider
{
    public bool LastValidationSuccessful {get; set;}
}

For instance:

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 ValidateChildren, I could use the code, for example:

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 is not suitable for cases where the controls being checked are not ordinary.

I would love to use a better approach. Any ideas?

EDIT Form.AutoValidate = EnableAllowFocusChange ( WinForms). , , ( ). , , ErrorProvider .

+3
1

, , , .

, 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;
        }
    }

, !

+3

Source: https://habr.com/ru/post/1732988/


All Articles