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

MD'*_*D's 3 .net c# events winforms

以下是我的代码,用于处理表单中可用的所有文本框的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;
        }
    }
Run Code Online (Sandbox Code Playgroud)

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

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

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

Han*_*ant 21

   c.LostFocus += new System.EventHandler(this.txtLostfocus);
Run Code Online (Sandbox Code Playgroud)

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属性来摆脱一次性的闪烁,如果它仍然困扰你.