2012-03-12 92 views
1

我在想這個問題有一段時間了,但實際上並沒有想出解決方案。我有2個不同的事件處理程序遞歸調用對方。一旦事件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)的組合框的選擇的索引改變事件:

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 2012-03-12 22:33:18

+0

爲什麼他們互相呼叫,不要調用任何提供您想要觸發的功能的方法? – 2012-03-12 22:33:45

+0

你有兩個選擇來處理這個問題。可能通過同步屬性限制遞歸,或者以不執行觸發其他事件的操作的方式設計事件處理代碼。無論哪種方式,你都沒有足夠的細節來提出答案。也許如果你發佈一些代碼? – JamieSee 2012-03-12 22:38:07

回答

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 2012-03-12 22:55:20

+0

是的,但是如果您重新查詢控件的數據源,則不容易看到這些值是否已更改。 – 2012-03-12 22:59:58

0

重構您的代碼,以便A調用DoSomethingA(),B調用DoSomethingB()。這樣,如果您希望A執行B的功能,則只需撥打DoSomethingB()即可,並且不會有任何遞歸調用。

+0

但是,如果事件A的處理程序中的某些事件引發事件B,則該代碼現在位於由A的處理程序調用的方法DoSomethingA中的事實不會停止遞歸;它只是添加更多的電話到堆棧(A-> doSomeA-> B-> doSomeB-> A-> doSomeA-> B - > ...-> SOE)。 – KeithS 2012-03-12 23:16:34

0

只需使用一個bool(也許稱爲dontFireA),並將其設置在一個只是調用乙

+0

我想過這個,但它並沒有解決潛在的問題。這可能是OP不是故意遞歸地發射這些事件。 – 2012-03-12 22:50:15

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