在处理多个文本框的获取和丢失焦点事件时,焦点和失去焦点都是重复事件调用,它进入无限循环

时间:2014-03-19 12:21:34

标签: c# .net winforms events

以下是我的代码,用于处理表格中所有文本框的gotfocus和lostfocus事件。

private void Form1_Load(object sender, EventArgs e)
    {

        foreach (Control c in this.Controls)
        {
            if (c is TextBox)
            {
                c.GotFocus += new System.EventHandler(this.txtGotFocus);
                c.LostFocus += new System.EventHandler(this.txtLostfocus);
            }
        }
    }
    private void txtGotFocus(object sender, EventArgs e)
    {
        TextBox tb = (TextBox)sender;
        if (tb != null)
        {
            tb.BackColor = Color.Silver;
            tb.BorderStyle = BorderStyle.FixedSingle;
        }

    }
    private void txtLostFocus(object sender, EventArgs e)
    {

        TextBox tb = (TextBox)sender;
        if (tb != null)
        {
            tb.BackColor = Color.White;
            tb.BorderStyle = BorderStyle.Fixed3D;
        }
    }

它可以在第一个文本框中正常工作,但是当我按Tab键转到下一个文本框时,它将重复调用这两个事件,文本框的行为就像闪烁一样。一段时间后,错误信息显示在代码中:

  

对类型为“System.Windows.Forms!System.Windows.Forms.NativeMethods + WndProc :: Invoke”的垃圾收集委托进行了回调。这可能会导致应用程序崩溃,损坏和数据丢失。将委托传递给非托管代码时,托管应用程序必须将它们保持活动状态,直到确保它们永远不会被调用为止。

代码有什么问题?有没有解决方案?

2 个答案:

答案 0 :(得分:20)

   c.LostFocus += new System.EventHandler(this.txtLostfocus);

LostFocus是一个危险的事件,Control.LostFocus的MSDN Library文章对此发出警告,强烈建议使用Leave事件。您可以在设计器中看到这一点,在表单上放置一个TextBox,然后单击“属性”窗口中的闪电图标。请注意GotFocus和LostFocus事件如何可见。您必须改为使用Enter和Leave事件。

有关此处发生的事情的一些背景知识。您的程序会因为分配BorderStyle属性而爆炸。那是一个很难的"属性,它是影响窗口样式标志的属性,是传递给本机CreateWindowEx()函数的标志。因此,更改边框样式需要Winforms再次创建本机窗口。这就是导致你看到闪烁的原因,文本框被破坏并重新创建,然后重新绘制。你看到了。

但是除了闪烁之外还有副作用,它还会导致低级别的GotFocus和LostFocus事件被触发。因为被破坏的窗户当然也失去了焦点。由于LostFocus事件处理程序再次更改BorderStyle,因此会在程序中进行非常差的交互,从而迫使Winforms再次重新创建窗口。并触发GotFocus事件,您再次更改BorderStyle。这反复重复,你看到文本框快速闪烁。这不会无休止地进行,经过10,000次创建窗口后,操作系统会拔出插件,并且不会让您的程序创建另一个。窗口程序的严重崩溃就是结果。

Enter和Leave事件没有问题,他们不能使用低级Windows通知,因此在重新创建文本框窗口时不要触发。如果它仍然困扰你,你只能通过不改变BorderStyle属性来摆脱一次性闪烁。

答案 1 :(得分:3)

这会导致您更改bordertyle。不要问我为什么,我不知道。如果您删除tb.BorderStyle = XXX,它将有效。我猜(!)更改bordertyle使控件松散其fokus(再次获得)

编辑:汉斯更快,有更好的解释:)