3

I have a TabControl with multiple TabPages which each contain multiple controls. When a user moves away from my tab using a button, I want to validate that the controls on that tab were modified correctly. Specifically, I want to check that they have selected a radio button.

What happens is that if validation fails (meaning, I set CancelEventArgs to true), the UI doesn't respond to input anymore. Controls still respond to hover and click (meaning, the color changes), but no action is taken. I can't navigate to other tabs, or even close the app using the "X" button.

I've tried adding an errorProvider, adding a SelectTab call, adding a Focus() call to both the tab and a control on the tab, and adding a MessageBox. The MessageBox allowed me to click OK, but then returned me to the "locked" UI. Adding the Focus() call to a control on the current tab (that failed validation) causes the next control to be selected, but the UI is still locked.

Any ideas why this is happening or how to get around it?

NOTE: This only happens if I try to change the tab using a button on the tab. If I just click on another tab, the cancellation works and I'm dropped back to my tab as expected with all controls usable.

EDIT: I've finally had time to revisit this. I created a simple 2 tab control with checkboxes that cancel the validation. I threw some other controls (radio buttons and text boxes) on the tabs to demonstrate the "locking", but they're not included here as there is no code behind them. This code illustrates the problem I'm having. Upon checking the checkbox and clicking button1, all controls become unresponsive. Code follows. Project files available on request.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace TabEventTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            tabControl1.SelectedIndex++;
        }

        private void button2_Click(object sender, EventArgs e)
        {
            tabControl1.SelectedIndex--;
        }

        private void tabPage2_Validating(object sender, CancelEventArgs e)
        {
            if (checkBox2.Checked)
            {
                e.Cancel = true;
            }
        }

        private void tabPage1_Validating(object sender, CancelEventArgs e)
        {
            if (checkBox1.Checked)
            {
                e.Cancel = true;
            }
        }
    }
}
Freefall
  • 73
  • 5
  • I have encountered a similar bug, which happens even when I simply click on the tabs. However, my textboxes are still working; the controls that locks up includes buttons, checkboxes, and nested tabControls. For some context, my Validating handler begins by showing a MessageBox (asking the user whether to save); if the result is "Cancel", I set e.Cancel = true. I am dropped back to the same page, and the UI locks up as described. – Imperishable Night May 23 '17 at 23:18

2 Answers2

1

After much research, I've come to the conclusion that this cannot be done using events raised at the TabPage level. I found one MSDN forum post from 2006 that was similar to my problem and the conclusion there was that this was a bug in the .NET framework. If that's true, it still hasn't been fixed from what I can see.

The way I accomplished the validation was by using the Deselecting Event on the TabControl. This means I have one event handler for all my tabs (and I then have custom validation functions that fire based on the tab being deselected), which is not as clean as I'd like, but it's functional. I couldn't use the Selecting Event as previously suggested as that only gave me the tab I was navigating TO, and I needed to validate the tab I was leaving FROM. I missed the existence of Deselecting the first time around.

Code from my event handler:

private void tabControl1_Deselecting(object sender, TabControlCancelEventArgs e)
{
    switch (e.TabPageIndex)
    {
        case 0: 
            if (!validateTab1())
            {
                e.Cancel = true;
            }
            break;
        case 1: 
            if (!validateTab2())
            {
                e.Cancel = true;
            }
            break;
        default:
            break;
    }
}
Freefall
  • 73
  • 5
0

It looks like you're using the validation handler incorrectly. Instead of forcing the tab control to go to or stay on a tab you should be using the CancelEventArgs parameter to cancel navigation.

Take a look at this MSDN article for documentation on the CancelEventArgs.Cancel Property and this Q/A thread for an explanation and code sample for your particular scenario.

You could also use the Tab Control's Selecting Event to perform validation and block a tab page change.

The Selecting event occurs before a tab is selected, enabling a handler to cancel the tab change.

In this case you would use the TabControlCancelEventArgs parameter to set Cancel = true;

Paul Sasik
  • 79,492
  • 20
  • 149
  • 189
  • I have e.Cancel = true. I also mentioned I tried removing the SelectTab call. Outside of that, I'm not sure how to use the CancelEventArgs to cancel navigation. – Freefall Jun 11 '14 at 19:07
  • Is your `tabPage4.CausesValidation` set to `true`? – Paul Sasik Jun 11 '14 at 19:09
  • Yes, as is the parent TabControl. – Freefall Jun 11 '14 at 19:14
  • I'm not quite sure what is going wrong for you. You mention removing the error provider and tab select calls but you also said that you put in a dialog box in place. Try *just doing* `e.Cancel = true;` Also see my edit for another validation/cancel option. – Paul Sasik Jun 11 '14 at 19:18
  • Seems like maybe I'm hitting an event bubbling issue. See my edit to OP. Heading back to the debugger for now. – Freefall Jun 11 '14 at 19:47
  • 1
    @Freefall: When encountering issues like this it can be helpful to isolate the problem. There are several ways but the cleanest is to create a new project from scratch, single form containing a single tab control which in turn contains two tab pages. Put a single control to validate on one of the tabs and test it. If it works with the procedure you've used then you start comparing the additional UI logic in your project and testing one aspect at a time. Good luck. – Paul Sasik Jun 11 '14 at 20:00