为什么这不会造成无限的事件循环呢?

我有一个简单的应用程序,反转任何文本input到另一个文本框中。 问题是,你可以修改任何一个文本框,这些改变将会被(反过来)反映在另一个文本框中。

我写这个代码,相信会导致问题。

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); } } 

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

根据注释,正如已经回答的那样,当您将Text属性设置为已有的值时, TextChanged事件不会被TextChanged

目前尚不清楚这是否可以安全依靠。 这是一个明智的优化,如果将来的.NET Framework版本放弃它,我会感到非常惊讶,但我不能说老版本,也不能为第三方实现(单声道)。

为了绝对安全,我不会在你的问题中使用Focused检查。 我会做什么Text设置现在做。

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

这与阻止无限recursion具有相同的优点,但可以更好地与其他代码一起使用,这些代码可以放在窗体中,从而将文本作为其他事件的结果进行更改。

它不会导致循环的原因是它检查Text属性是否实际改变,即如果新值不等于旧值。 在你的情况下, mirror函数恰好相反,这导致了两遍后相同的文本。

这很容易检查。

首先,replace两个文本框控件

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

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

  • 名称
  • 文本

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

第一次rest:

  • 名称:“mirrorText”
  • 文字:“”
  • 价值:“321”

第二次rest:

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

第三…哎呀,它不会中断了。 为了检测为什么我们必须更深入。 看参考文献:文本框设置器没有什么不寻常的,但TextBoxBase的一个看起来很有趣 :

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

所以,正如hvd已经回答,原因是文本框不会引发TextChanged如果新旧值是相同的。 我不认为这种行为会改变,至less对于WinForms来说。 但如果你想要更强大的解决scheme,这里是:

  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"); } 

PS镜像()将在代理对上失败。 这里有一些解决scheme。

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