2个事件互相呼叫

时间:2012-03-12 22:30:58

标签: c# event-handling

我想知道这个问题已经有一段时间了,但实际上并没有找到解决方案。我有2个不同的事件处理程序递归调用彼此。一旦事件A被触发,它就会触发事件B,再次触发事件A,依此类推......

基本上我希望能够在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.
}

什么是最好的解决方案,以确保他们每个人都“做他们的事情”,并且不会在这样做时解雇其他事件?

5 个答案:

答案 0 :(得分: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;
    ...
}

答案 1 :(得分:0)

重构您的代码,以便A调用DoSomethingA(),B调用DoSomethingB()。这样,如果您希望A执行B的功能,您只需调用DoSomethingB()而不进行任何递归调用。

答案 2 :(得分:0)

只需使用bool(也许称为dontFireA)并在调用B之前将其设置为A

答案 3 :(得分: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​​(value - myField)> someConstant)来打破递归。

你能否对你的问题采用类似的技巧?

如果两个事件都在同一个对象上,或者所有者互相引用,您也可以在每个事件上存储一个标记。

private void OnEvent()
{
    DoSomething();
}

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

    // do work

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

答案 4 :(得分:0)

我将做出有根据的猜测,即你不是自己提出事件A或事件B;假设事件A是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事件,从而导致无限递归。

如果你想要只运行一次,那么你可以做的第一件事就是标记它们已经在运行(更改另一个文本框的文本会导致该文本框的事件处理程序在同一个调用堆栈中运行:

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