当前位置: 动力学知识库 > 问答 > 编程问答 >

c# - Preventing event handler loop

问题描述:

I have a form with two text fields, A and B that are supposed to behave in the following way:

  • Typing something into A should set B.Text = f(A.Text)
  • Typing something into B should set A.Text = g(B.Text)

...for some arbitrary and potentially unrelated functions f and g.

The problem I'm facing is that the naive implementation of simply throwing the above code into each field's handler will create an infinite loop as A's handler will update B's value and call B's handler, which will update A, etc.

What would be the correct (and preferably thread-safe) way to handle this? Either somehow determining whether a change was done manually or programmatically, somehow suppressing events firing when changing the value, or some other way.

网友答案:

I assume you're using TextChanged event, try this then:

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

Anyway, a better way to just edit A when the user is finished with B(finished whatever he wanted to write in it), that's because if expression will be evaluated at every character the user inputs.
By the way, changing a text while the user writes might be surprising to him, so better to avoid textchanged event in this case.

网友答案:

Use a flag to signal that you are doing changes

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

You don't have to care about thread-safety as this all happens in the unique UI-thread. UI events never create new threads; i.e. an event (click, text changed, etc.) never interrupts another one!


If you want to be sure that the flag is reset, you can use the try-finally statement. The finally block is ensured to run, even if an exception should occur within the try block (unless the application is terminated unexpectedly).

if (!updating) {
    updating = true;
    try {
        A.Text = f(B.Text);
    } finally {
        updating = false;
    }
}
分享给朋友:
您可能感兴趣的文章:
随机阅读: