在.NET中如何在验证后将焦点设置到控件上

6
我有一个WinForm应用程序,其中包含几个输入控件。在验证事件处理程序(ValidatingValidated)中,我需要根据验证的值确定下一个要激活的控件。
在Microsoft的Validating事件的文档中,它指出:
警告 不要尝试在Enter、GotFocus、Leave、LostFocus、Validating或Validated事件处理程序中设置焦点。这样做可能会导致您的应用程序或操作系统停止响应。有关详细信息,请参阅“键盘输入参考”部分中的WM_KILLFOCUS主题,以及MSDN库中“关于消息和消息队列”主题的“消息死锁”部分。
对于Form类,有一个ActiveControl属性,允许设置要成为活动控件的控件,并且没有提到任何限制。在经过数小时的网络搜索后,我没有找到其他解决方案。
从我的Validated事件处理程序设置ActiveControl属性(而不是Focus),是否是安全的方法来积极激活我想要的控件?如果不是,是否有其他解决方案?
由于.NET Compact Framework没有ActiveControl属性,有人能提出解决方案吗?
4个回答

11

确实,在验证事件期间更改焦点是相当麻烦的。事件在焦点改变的确切时刻被触发。对于Windows来说,下一个控件已经获得了焦点,但逻辑表单状态仍然将焦点放在正在验证的控件上。当您将e.Cancel设置为true时,Winforms必须撤消Windows的焦点状态。如果不这样做,它必须在事件之后更新逻辑状态。当您自己更改焦点时,有各种各样的问题可能会出现。

重要的是等到焦点问题解决之后再继续执行代码。最好的方法是延迟代码执行直到一切都完成并且窗体再次处于空闲状态。您可以使用Control.BeginInvoke()方法干净地实现这一点。像这样:

    private delegate void ChangeFocusDelegate(Control ctl);

    private void textBox1_Validating(object sender, CancelEventArgs e) {
        int value;
        if (!int.TryParse(textBox1.Text, out value)) e.Cancel = true;
        else {
            if (value == 1) this.BeginInvoke(new ChangeFocusDelegate(changeFocus), textBox2);
            else this.BeginInvoke(new ChangeFocusDelegate(changeFocus), textBox3);
        }
    }
    private void changeFocus(Control ctl) {
        ctl.Focus();
    }

哇,聪明的回答!我以为委托方法必须调用EndInvoke(),但那是在我了解Delegate.BeginInvoke()和Control.BeginInvoke()之间的区别之前。请参见[.net - Invoke()和BeginInvoke()之间的区别是什么?][1][1]https://dev59.com/zXVC5IYBdhLWcg3woStW - Suncat2000

3

你尝试过将传递给Validating事件处理程序的CancelEventArgsCancel属性设置为False吗?

这是保持焦点在当前控件上并防止下一个控件获取焦点(如果验证失败)的预期方法。例如:

private void TextBox1_Validating(object sender, System.ComponentModel.CancelEventArgs e)
{
    //Make sure that the textbox is not left blank
    if (string.IsNullOrEmpty(TextBox1.Text))
    {
        e.Cancel = true;
    }
}

谢谢。我知道这个,但它只能防止焦点改变,不能将焦点设置到特定的控件上。 - Suncat2000
@Suncat:是的,我无法从问题中了解到您想将焦点设置为不同控件。Hans已经给出了一个很好的答案来实现这一点。 - Cody Gray

0

这个帖子很旧了,但我有几个想法:

  1. 每个控件都有一个Tag属性。你可以给你想要聚焦的控件赋予一个唯一的Tag值,然后创建一个方法来遍历控件以找到该控件。然后你就可以将焦点设置在它上面。

  2. 不要使用Validating事件,为什么不使用Leaving事件呢?看起来没有同样的怪癖。


0

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