防止事件处理程序循环

本文关键字:循环 程序 事件处理 | 更新日期: 2023-09-27 18:36:00

我有一个包含两个文本字段的表单,AB,它们的行为方式如下:

  • A中键入某些内容应该可以设置B.Text = f(A.Text)
  • B中键入某些内容应该可以设置A.Text = g(B.Text)

。对于一些任意且可能不相关的功能fg

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

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

防止事件处理程序循环

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

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 语句。finally 块确保运行,即使 try 块中发生异常(除非应用程序意外终止)。

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

我假设您正在使用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 的更好方法(完成他想写的任何内容),这是因为如果表达式将在用户输入的每个字符处进行评估。
顺便说一下,在用户写入时更改文本可能会让他感到惊讶,因此在这种情况下最好避免文本更改事件。