2015-01-03 2 views
0

У меня есть форма с двумя текстовыми полями, A и B, которые должны вести себя следующим образом:Предотвращение цикла обработчика событий

  • Typing что-то в A следует установить B.Text = f(A.Text)
  • Typing что-то в B должен набор A.Text = g(B.Text)

... для некоторых произвольных и потенциально несвязанных функций f и g ,

Проблема я столкнулся в том, что наивная реализация просто бросать выше код в обработчик каждого поля будет создавать бесконечный цикл как A «s обработчик обновит B» значение s и вызвать обработчик B «s, который будет обновление A и т. д.

Что было бы правильным (и, желательно, потокобезопасным) способом справиться с этим? Или каким-то образом определяли, было ли изменение сделано вручную или программно, каким-то образом подавляя события, срабатывающие при изменении значения, или каким-либо другим способом.

+0

Вы можете использовать событие KeyPressed вместо того, что вы в настоящее время используете (TextChanged?). –

+0

К сожалению, 'KeyPress' вызывается перед обновлением« Текста », что затрудняет определение того, каким будет результат« Text ». – Smallhacker

+0

А как насчет события 'OnLostFocus' в элементе управления? –

ответ

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 (законченный, что он хотел написать в нем) , это потому, что если выражение будет оцениваться на каждом символе, который вводит пользователь.
Кстати, изменение текста во время записи пользователем может показаться ему неожиданным, поэтому лучше избегать события с изменением текста в этом случае.

1

Используйте флаг, чтобы сигнализировать, что вы делаете изменения

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-потоке. События пользовательского интерфейса никогда не создают новые потоки; то есть событие (щелчок, изменение текста и т. д.) никогда не прерывает другого!


Если вы хотите быть уверены, что флаг сброшен, вы можете использовать инструкцию try-finally. Окончательный блок обеспечивает выполнение, даже если в блоке try должно произойти исключение (если приложение не будет неожиданно прекращено).

if (!updating) { 
    updating = true; 
    try { 
     A.Text = f(B.Text); 
    } finally { 
     updating = false; 
    } 
} 
Смежные вопросы