防止事件处理程序循环

时间:2015-01-03 22:28:08

标签: c# winforms event-handling

我有一个包含两个文本字段AB的表单,它们应按以下方式运行:

  • A中输入内容时应设置B.Text = f(A.Text)
  • B中输入内容时应设置A.Text = g(B.Text)

...对于某些任意且可能不相关的函数fg

我面临的问题是,简单地将上述代码抛入每个字段的处理程序的简单实现将创建一个无限循环,因为A的处理程序将更新B的值并调用B的处理程序,它将更新A等。

处理此问题的正确方法(最好是线程安全的)是什么?以某种方式确定更改是手动还是以编程方式完成,以某种方式抑制在更改值时触发的事件,或者其他方式。

2 个答案:

答案 0 :(得分:2)

使用标志表示您正在进行更改

private bool updating;

private void A_TextChanged(object sender, EventArgs e)
{
    if (!updating) {
        updating = true;
        B.Text = f(A.Text);
        updating = false;
    }
}

private void B_TextChanged(object sender, EventArgs e)
{
    if (!updating) {
        updating = true;
        A.Text = g(B.Text);
        updating = false;
    }
}

您不必关心线程安全,因为这一切都发生在独特的UI线程中。 UI事件永远不会创建新线程;即一个事件(点击,文本改变等)永远不会打断另一个事件!


如果要确保重置该标志,可以使用try-finally语句。即使在try块中发生异常,也确保运行finally块(除非应用程序意外终止)。

if (!updating) {
    updating = true;
    try {
        A.Text = f(B.Text);
    } finally {
        updating = false;
    }
}

答案 1 :(得分:1)

我假设您正在使用TextChanged事件,请尝试:

private bool callB=true;
private bool callA=false;
private void A_Click(object sender, System.EventArgs e)
{
    callB=true;
    callA=false;
}
private void B_Click(object sender, System.EventArgs e)
{
    callB=false;
    callA=true;
}
private void A_textchanged(object sender, RoutedEventArgs e)
{        
    if(callB)        
       B.text=f(A.text);                  
}
private void B_textchanged(object sender, RoutedEventArgs e)
{
    if(callA)        
        A.text=g(B.text);                    
}

无论如何,当用户完成B(完成他想写的任何内容)时,更好的方法就是编辑A,这是因为如果表达式将在用户输入的每个字符上进行评估。
顺便说一句,在用户写入时更改文本可能会令他感到惊讶,因此在这种情况下最好避免使用textchanged事件。