Winforms: 不能在Validating时弹出有模式的对话框

一、问题重现步骤:                                              

1.       新建一个Winforms项目;

2.       在项目中添加一个UserControl,并在里面添加两个TextBoxtextBox1textBox2

3.       编译该项目;

4.       Toolbox里找到我们添加的UserControl1,并在Form1上添加一个实例userControl11

5.       Form1添加一个TextBox,命名为textBox3

6.       textBox3添加如下事件处理器(Event Handler):

private void textBox3_Validating(object sender, CancelEventArgs e)

{

    MessageBox.Show("textBox3_Validating", "Info");

}

7.       编译、运行;

8.       鼠标点击textBox3,再点击userControl11上的textBox2

9.       textBox3_Validating被触发,会弹出一个消息框。点击确认按钮让消息框消失。此时光标在textBox2中;

10.   用键盘输入“abc

 

结果:“abc”出现在textBox1

 

二、分析:

         MessageBox是一个有模式的对话框。当出现一个MessageBox的时候,该MessageBox有自己的消息队列,同时屏蔽Form1的消息队列。所以一旦MessageBox弹出来的时候,Form1就不能响应键盘、鼠标等消息了。当我们点击确认按钮让MessageBox消失的时候,在MessageBox的内部会重新把焦点(Focus)设回到Form1,这样Form1可以继续响应消息。当把焦点设回到Form1时,Winforms会试着让焦点停在Form1上一个可以设置焦点的控件上,在我们这个场景下找到的是textBox1。由于我们点击了textBox2Winforms同时有试着把焦点设到textBox2,此时就出现了我们前面看到的问题:焦点看起来是在textBox2(因为光标在textBox2),但实际上在textBox1(输入的字符在textBox1)。

textBox3_Validating是在Form1的消息处理过程中被触发了,如果在该事件处理器中弹出一个有模式的对话框,Form1上的消息处理被屏蔽。当焦点重新回到Form1上的时候,它的消息队列已经混乱了。

textBox3_Validating更加复杂的是,Validating是一个可以取消的事件。当e.Canceltrue的时候,事件处理完后焦点应该仍停在textBox3上;当e.Cancelfalse的时候,焦点会设到下一个控件上。在我们的场景里,是textBox2。也就是说,在textBox3_Validating处理结束后,下一个焦点会在那个控件上还是未知的,取决于e.Cancel的值。可是如果弹出一个对话框,在对话框消失的时候会去设置焦点,这个时候无论设到哪个控件上都有可能是错误的。

三、建议

         不要在Validating的处理器中弹出对话框。这样会打乱消息队列,很容易导致错误。

         如果想绕过(不是解决)前面提到问题,一个办法是用BeginInvoke来弹出对话框。代码如下:

        private void textBox3_Validating(object sender, CancelEventArgs e)

        {

            textBox3.BeginInvoke(new ShowMessageBoxDelegate(ShowMessageBox));

        }

 

        private delegate void ShowMessageBoxDelegate();

 

        private void ShowMessageBox()

        {

            MessageBox.Show("textBox3_Validating", "Info");

        }

    值得一提的是,该方法不能解决所有的问题。比如当焦点在textBox3的时候去点击textBox2textBox2是不能收到WM_LBUTTONUP的消息的。因此还是回到前面的建议,不要在Validating中弹出有模式的对话框。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值