取消 TabPage.Validating 会锁定我的界面

3
我有一个TabControl,其中包含多个TabPage,每个TabPage都包含多个控件。当用户使用按钮移动离开我的选项卡时,我希望验证该选项卡上的控件是否正确修改。具体而言,我想检查他们是否选择了单选按钮。
问题在于,如果验证失败(即,我将CancelEventArgs设置为true),则UI不再响应输入。控件仍然响应悬停和单击(即,颜色会改变),但不执行任何操作。我无法导航到其他选项卡,甚至不能使用“X”按钮关闭应用程序。
我尝试添加了errorProvider,添加了SelectTab调用,向选项卡和选项卡上的控件添加了Focus()调用,并添加了MessageBox。 MessageBox允许我点击确定,但然后将我返回到“锁定”的UI。将Focus()调用添加到当前选项卡上的控件(未通过验证)会导致选择下一个控件,但UI仍然被锁定。
有任何想法为什么会发生这种情况或如何绕过它吗?
注意:只有在我尝试使用选项卡上的按钮更改选项卡时才会发生这种情况。如果我只是单击另一个选项卡,则取消操作起作用,并且可以返回到我的选项卡,所有控件都可用。
编辑: 我最终有时间重新访问这个问题。我创建了一个简单的2选项卡控件,其中包含复选框以取消验证。我在选项卡上放置了一些其他控件(单选按钮和文本框)来演示“锁定”,但它们没有包含在此处,因为它们没有代码支持。此代码说明了我遇到的问题。勾选复选框并单击button1后,所有控件都变得无响应。代码如下。项目文件可根据要求提供。
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;
            }
        }
    }
}

我遇到了一个类似的错误,即使我只是点击选项卡也会发生。然而,我的文本框仍然可以工作;锁定的控件包括按钮、复选框和嵌套的选项卡控件。为了一些背景信息,我的验证处理程序首先显示一个消息框(询问用户是否保存);如果结果是“取消”,我设置e.Cancel = true。我被放回到同一页,并且UI像描述的那样被锁定。 - Imperishable Night
2个回答

1
经过深入的研究,我得出结论:无法使用TabPage级别引发事件来完成此操作。我找到了一个2006年的MSDN论坛帖子,与我的问题类似,那里的结论是这是.NET框架中的一个bug。如果这是真的,从我看到的情况来看,它仍然没有被修复。
我实现验证的方式是使用TabControl上的Deselecting Event。这意味着我有一个事件处理程序适用于我所有的选项卡(然后我有自定义验证函数根据要取消选择的标签页进行触发),虽然不够干净,但它是可用的。我不能像之前建议的那样使用Selecting事件,因为那只给了我我要导航到的选项卡,而我需要验证我要离开的选项卡。第一次我没有注意到Deselecting的存在。
我的事件处理程序代码:
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;
    }
}

0

看起来您正在错误地使用验证处理程序。 您应该使用 CancelEventArgs 参数来取消导航,而不是强制选项卡控件进入或停留在选项卡上。

请参阅 此 MSDN 文章 以获取 CancelEventArgs.Cancel 属性文档,并参考 此 Q/A 线程 获取特定情况的解释和代码示例。

您还可以使用 选项卡控件的 Selecting 事件 来执行验证并阻止选项卡页更改。

Selecting 事件在选择选项卡之前发生,使处理程序可以取消选项卡更改。

在这种情况下,您可以使用 TabControlCancelEventArgs 参数来设置 Cancel = true;

我已经设置了 e.Cancel = true。我还提到过尝试移除 SelectTab 调用。除此之外,我不知道如何使用 CancelEventArgs 来取消导航。 - Freefall
你的 tabPage4.CausesValidation 是否设置为 true 了? - Paul Sasik
是的,就像父级TabControl一样。 - Freefall
我不太确定你遇到了什么问题。你提到删除了错误提供程序和选项卡选择调用,但你也说你放置了一个对话框。尝试只做 e.Cancel = true; 另外,请查看我的编辑以获取另一种验证/取消选项。 - Paul Sasik
似乎我可能遇到了一个事件冒泡的问题。请看我对原始帖子的编辑。暂时回到调试器继续工作。 - Freefall
1
@Freefall:当遇到这样的问题时,隔离问题可能会有所帮助。有几种方法,但最干净的方法是从头开始创建一个新项目,单个表单包含一个单独的选项卡控件,该控件又包含两个选项卡页面。在其中一个选项卡上放置一个要验证的单个控件并进行测试。如果它使用了您使用的过程而起作用,则可以开始比较项目中的其他UI逻辑,并逐个测试一个方面。祝你好运。 - Paul Sasik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接