【问题标题】:Why isn't this causing an infinite loop of events?为什么这不会导致事件的无限循环?
【发布时间】:2015-01-16 20:11:07
【问题描述】:

我有一个简单的应用程序,可以反转在另一个文本框中键入的任何文本。问题是,您可以修改任一文本框,并且更改将(字面上)反映在另一个文本框中。

我写了这段代码,相信它会引起问题。

private void realText_TextChanged(object sender, EventArgs e)
{
    mirrorText.Text = mirror(realText.Text);
}

private void mirrorText_TextChanged(object sender, EventArgs e)
{
    realText.Text = mirror(mirrorText.Text);
}

private string mirror(string text)
{
    return new string(text.Reverse().ToArray()).Replace("\n\r", "\r\n");
}

然后我尝试了一下,认为它会导致无限循环(realText 更改 mirrorText,另一个事件发生,mirrorText 更改 realText 等)。但是,除了预期的行为之外,什么都没有发生。

我当然很高兴,我可以把它留在这里。 或者我可以吗?

我很确定TextChanged 事件应该在Text 更改时触发。这是事件中某些错误保护的预期行为,还是我只是幸运?此代码是否可以在另一台计算机上使用其他构建设置等出现异常?它可以很容易地修复:

private void realText_TextChanged(object sender, EventArgs e)
{
    if (realText.Focused)
    {
        mirrorText.Text = Mirror(realText.Text);
    }
}

为了安全起见,我可能还是会这样做,但是否需要检查? (我什至不会问是否推荐。)

【问题讨论】:

  • 我很确定 TextChanged 事件仅在从 UI 而非代码更改文本时触发。
  • 来自 MSDN 的@Magnus:如果 Text 属性被编程修改或用户交互更改,则会引发此事件。
  • @Magnus,您可以使用 Reflector(我想这就是它的名称,对吗?或者 JetBrains 的...呃...记不起名字了)来检查一下!
  • Text 设置为已有的值可能不会触发TextChanged 事件,因为它实际上并没有改变。
  • @Marton,IDE 内的文档也说Event raised when the value of the Text property is changed on Control

标签: c# .net winforms events textchanged


【解决方案1】:

很容易检查。

首先,将两个文本框控件替换为

    class T : TextBox
    {
        public override string Text
        {
            get
            {
                return base.Text;
            }
            set
            {
                base.Text = value;
            }
        }
    }

其次,在setter上设置断点。将这些表达式添加到 Watch 窗口:

  • 姓名
  • 文字
  • 价值

第三,启动应用程序,从某处复制“123”并将其粘贴到第一个文本框中。就是这样:

第一次休息:

  • 名称:“mirrorText”
  • 文本:“”
  • 值:“321”

第二次休息:

  • 名称:“realText”
  • 文字:“123”
  • 值:“123”

第三...哎呀,它不再坏了。为了检测为什么我们必须更深入。看参考来源:text box setter does nothing不寻常,但是TextBoxBase的一个looks interesting

        set {
            if (value != base.Text) { // Gotcha!
                base.Text = value;
                if (IsHandleCreated) {
                    // clear the modified flag
                    SendMessage(NativeMethods.EM_SETMODIFY, 0, 0);
                }
            }
        }

所以,正如 hvd 已经回答的那样,原因是如果旧值和新值相同,文本框不会引发 TextChanged。我不认为行为会改变,至少对于winforms。但是,如果您想要更强大的解决方案,这里是:

    private void RunOnce(ref bool flag, Action callback)
    {
        if (!flag)
        {
            try
            {
                flag = true;
                callback();
            }
            finally
            {
                flag = false;
            }
        }
    }

    private bool inMirror;
    private void realText_TextChanged(object sender, EventArgs e)
    {
        RunOnce(ref inMirror, () =>
        {
            mirrorText.Text = mirror(realText.Text);
        });
    }

    private void mirrorText_TextChanged(object sender, EventArgs e)
    {
        RunOnce(ref inMirror, () =>
        {
            realText.Text = mirror(mirrorText.Text);
        });
    }

    private string mirror(string text)
    {
        return new string(text.Reverse().ToArray()).Replace("\n\r", "\r\n");
    }

附: mirror() 将在代理对上失败。 Here're一些解决方案。

【讨论】:

  • 感谢您进行更深入的检查。不过,我可能只会使用简单的 TextBox。顺便说一句,我重写了 mirror() 来做其他事情,那只是为了测试 GUI。
【解决方案2】:

如果文本框有一个文本,并且我们尝试用相同的文本更改它,则不会引发 TextChange 事件,因为新文本与以前的文本相同。 在您的代码中,realText_TextChanged 事件反转文本并使用它更改 mirrorText。 mirrorText_TextChanged 事件反转文本并尝试更改 realText。 realText 已经有这个文本并且不会引发 realText_TextChanged 事件。

【讨论】:

    【解决方案3】:

    根据 cmets,正如已经回答的那样,当您将 Text 属性设置为它已有的值时,不会引发 TextChanged 事件。

    尚不清楚这是否是您可以安全依赖的东西。这是一个明智的优化,如果 .NET Framework 的未来版本放弃它,我会感到非常惊讶,但我不能代表旧版本,也不能代表第三方实现 (Mono)。

    为了绝对安全,我将使用Focused检查您在问题中提出的问题。我会完全Text setter 现在所做的事情。

    private void realText_TextChanged(object sender, EventArgs e)
    {
        var newMirrorText = Mirror(realText.Text);
        if (mirrorText.Text != newMirrorText)
            mirrorText.Text = newMirrorText;
    }
    

    这具有防止无限递归的相同优势,但可以更好地与您可能放入表单中的其他代码配合使用,这些代码会因某些其他事件而更改文本。

    【讨论】:

      【解决方案4】:

      它不会导致循环的原因是它检查Text 属性是否实际更改,即新值是否不等于旧值。在您的情况下,mirror 函数恰好会反转自身,这会在两次传递后导致相同的文本。

      【讨论】:

      • @Pietu1998(和@Basic):感谢您的编辑。只好自己推迟编辑,回来时发现已经有两个完美的编辑了。
      • 很抱歉,但我会接受 [user:hvd],因为他们首先建议并发布了更全面的答案。不过,我很感激你的回答。
      • @Pietu1998:别担心 :)
      猜你喜欢
      • 1970-01-01
      • 2013-06-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-08
      • 2014-05-06
      • 1970-01-01
      • 2012-09-27
      相关资源
      最近更新 更多