Cancelling TabPage.Validating locks my UI

539 Views Asked by At

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

There are 2 best solutions below

0
Freefall On BEST ANSWER

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;
    }
}
6
Paul Sasik On

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;