2012-03-12 3 views
1

Мне было интересно об этой проблеме некоторое время, но на самом деле не могло найти решения. У меня есть два разных обработчика событий, вызывающих друг друга рекурсивно. Как только событие A запущено, оно вызывает событие B, которое вызывает событие A снова и так далее.2 события, вызывающие друг друга

В принципе, я хочу, чтобы иметь возможность выбирать текст в RichTextBox и показывать соответствующий размер шрифта в поле со списком. Когда я выбираю другой размер шрифта из ComboBox, я хочу, чтобы его значение применялось к выбранному тексту.

В 2 события:

1) Выбор изменилось событие текста внутри RichTextBox:

private void MyRTB_SelectionChanged(object sender, RoutedEventArgs e) 
{ 
    //Get the font size of selected text and select the concurrent size from the ComboBox. 
} 

2) Выбранный индекс изменился случае Combobox:

private void CmbFont_SelectionChanged(object sender, SelectionChangedEventArgs e) 
{ 
    //Apply the chosen font size to the currently selected text of the RichTextBox. 
} 

Что было бы лучшим решением, чтобы убедиться, что каждый из них «делает свое дело» и не запускает другое событие?

+2

Не могли бы вы более подробно описать, какую проблему вы решаете? Я думаю, что мы сможем дать вам лучший ответ, если бы у нас был лучший контекст, чем событие A запускает событие B, которое рекурсивно запускает событие A. Некоторое изменение должно произойти. – TheGeekYouNeed

+0

Почему они называют друг друга и не называют какой-либо метод, который предоставляет функции, которые вы хотите вызвать? –

+0

У вас есть два варианта решения этой проблемы. Установите предел для вашей рекурсии, возможно, через свойство синхронизации или создайте код обработки событий таким образом, чтобы не выполнять операции, которые запускают дополнительные события. В любом случае, у вас недостаточно подробностей, чтобы предложить ответ. Может быть, если вы разместите какой-нибудь код? – JamieSee

ответ

1

Иногда изменение свойства элемента управления в коде вызывает непреднамеренное событие. Например, для изменения источника данных ListBox или ComboBox будет запускаться событие SelectedIndexChanged. Используйте флаг обрабатывать этот случай

private bool _loading; 

... 

_loading = true; 
// Fill the ComboBox or ListView here 
_loading = false; 

В обработчике событий делают этот

private void listBox1_SelectedIndexChanged(object sender, EventArgs e) 
{ 
    if (_loading) return; 
    ... 
} 
+0

это была одна из моих рекомендаций; другой должен был убедиться, что вы не измените что-то на равное, но другое значение ссылки. – KeithS

+0

Да, однако, если вы запрашиваете источник данных элемента управления, неясно, изменились ли значения. –

0

Рефакторинг вашего кода, чтобы A звонки DoSomethingA() и B звонки DoSomethingB(). Таким образом, если вы хотите, чтобы A выполнял функции B, вы можете просто позвонить DoSomethingB() и не иметь никаких рекурсивных вызовов.

+0

Но если что-то в обработчике события A поднимает событие B, то тот факт, что этот код теперь находится в методе DoSomethingA, вызываемом обработчиком A, не остановит рекурсию; он просто добавит больше вызовов в стек (A-> doSomeA-> B-> doSomeB-> A-> doSomeA-> B -> ...-> SOE). – KeithS

0

Просто используйте логическое значение (возможно, под названием dontFireA) и установить его в как раз перед вызовом B

+0

Я думал об этом, но он не решает основной проблемы. Вероятно, ОП не рекурсивно уволил эти события намеренно. –

0

уведомляя свойства (используется для того, чтобы дать возможность связывания с WPF не-WPF Недвижимость Болгария Недвижимость) использовать эту технику:

public object MyProperty 
{ 
    get 
    { 
     return myField; 
    } 
    set 
    { 
     if (value != myField) 
     { 
      myField = value; 
      NotifyProperyChanged("MyProperty"); // raise event 
     } 
    } 
} 

Условие if (value! = MyField) предотвращает бесконечную рекурсию (stackoverflowexception). В некоторых случаях (например, числа с плавающей запятой и неточные переводы значений), если вместо разложения рекурсии используется (Math.Abs ​​(значение - myField)> someConstant).

Не могли бы вы применить аналогичную технику к вашей проблеме?

Если оба события находятся на одном объекте или владельцы имеют ссылки друг на друга, вы также можете сохранить флаг на каждом, например.

private void OnEvent() 
{ 
    DoSomething(); 
} 

private void DoSomething() 
{ 
    this.IsBusy = true; 

    // do work 

    // raise event 
    if (!other.IsBusy) 
     RaiseEvent(); 
} 
0

я собираюсь сделать обоснованное предположение, что вы не поднимая событие A или событие B себя; скажем, событие А событие TextBox1.TextChanged и событие B это событие TextBox2.TextChanged, и у них есть обработчики, как:

public void Textbox1_TextChanged(object sender, EventArgs e) 
{ 
    ... 
    TextBox2.Text = someString; 
} 

public void Textbox2_TextChanged(object sender, EventArgs e) 
{ 
    ... 
    TextBox1.Text = someOtherString; 
} 

В этом случае обработчики каждый собирается поднять TextChanged событие другого TextBox путем в силу изменения текста, что приводит к бесконечной рекурсии.

Первое, что вы можете сделать, если хотите, чтобы оба запускались только один раз и только один раз, - это отметить, что они уже запущены (изменение текста другого текстового поля приводит к тому, что обработчик событий в текстовом поле работает в одном вызове стек:

public void Textbox1_TextChanged(object sender, EventArgs e) 
{ 
    if(handler1Running) return; //the second time through we exit immediately 
    handler1Running = true; 
    ... 
    TextBox2.Text = "Something"; //the other event handler is invoked immediately 

    handler1Running = false; 
} 

public void Textbox2_TextChanged(object sender, EventArgs e) 
{ 
    if(handler2Running) return; //the second time through we exit immediately 
    handler2Running = true; 
    ... 
    TextBox1.Text = "Something Else"; //the other event handler is invoked immediately 

    handler2Running = false; 
} 

Теперь, самые глубокая она будет идти три уровня; 1 в обработчик вызывает обработчик 2, который вызывающий обработчик 1 снова, который видит, что 1 в обработчик уже запущен и завершает работу, прежде чем делать что-либо, что углубится рекурсия. То же самое, если вы начнете с изменения TextBox2.

Другое, что вы можете сделать, это убедиться, что вы Не пытайтесь установить текстовое поле на то же значение, которое уже существует. Изменяя одну ссылку на другую, даже если обе ссылки имеют одно и то же строковое значение, загорается событие TextChanged. Если рекурсия должна продолжаться естественным образом, но достигнет устойчивого состояния, на самом деле это первое, что нужно попробовать:

public void Textbox1_TextChanged(object sender, EventArgs e) 
{ 
    StringBuilder builder = new StringBuilder(); 

    ... //build string 

    //now, even though the builder's ToString will produce a different reference, 
    //we're making sure we don't unnecessarily change the text. 
    if(builder.ToString != TextBox2.Text) 
     TextBox2.Text = builder.ToString();  
} 

public void Textbox2_TextChanged(object sender, EventArgs e) 
{ 
    StringBuilder builder = new StringBuilder(); 

    ... //build string 

    //now, even though the builder's ToString will produce a different reference, 
    //we're making sure we don't unnecessarily change the text. 
    if(builder.ToString != TextBox1.Text) 
     TextBox1.Text = builder.ToString();  
} 
Смежные вопросы