2013-09-27 45 views
2

我正在尋找一個簡潔的解決方案,用於臨時取消訂閱WinForm事件。舉例來說,如果我有以下事件處理textBox1的控制:乾淨的解決方案,暫時取消訂閱事件

private void textBox1_TextChanged(object sender, EventArgs eventArgs) 
{ 
    // Do something 
} 

我不希望這個事件,火災,當我以編程方式更改文本框的內容。但不是寫:

try 
    { 
    textBox1.TextChanged -= textBox1_TextChanged; 
    // Change textbox contents without triggering event 
    } 
    finally 
    { 
    textBox1.TextChanged += textBox1_TextChanged; 
    } 

我要找的東西,我可以使用類似於此:

using(new EventInhibitor(textBox1.TextChanged, textBox1_TextChanged)) 
{ 
    // Change textbox contents without triggering event 
} 

問題是我怎麼能textBox1.TextChanged事件傳遞給構造函數?反射?表達式?

public class EventInhibitor : IDisposable 
{ 
    private bool _disposed = false; 
    private XXX _event; 
    private EventHandler _handler; 

    public EventInhibitor(XXX event, EventHandler handler) 
    { 
    _event = event; 
    _handler = handler; 
    _event -= _handler; 
    } 

    public void Dispose() 
    { 
    if(_disposed) 
     return: 
    _event += _handler; 
    _event = null; 
    _handler = null; 
    _disposed = true; 
    } 
} 
+0

這是一個奇怪的問題。您希望在設置Text屬性的行上發生什麼樣的異常?如果在賦值的右邊有很多東西,那麼在設置Text屬性之前應該先處理它,然後在try..catch中進行處理,然後您不必重新建立事件處理程序。 –

+0

http://stackoverflow.com/questions/744494/winforms-temporarily-disable-an-event-handler –

+0

'textBox1.TextChanged - = textBox1_TextChanged;'**不會拋出異常**。 –

回答

2

您將不得不使用反射(所以不要忘記導入System.Reflection)。您可以通過控制(或者,如果你希望它是更通用的對象),而該事件以字符串形式的名稱:

public class EventInhibitor : IDisposable 
{ 
    private bool _disposed = false; 
    private EventInfo _event; 
    private EventHandler _handler; 
    private Control _control; 

    public EventInhibitor(Control c, string EventName, EventHandler handler) 
    { 
    _event = c.GetType().GetEvent(EventName); 
    _handler = handler; 
    _control = c; 
    _event.RemoveEventHandler(_control, _handler); 
    } 

    public void Dispose() 
    { 
     if (_disposed) 
      return; 

     _event.AddEventHandler(_control, _handler); 
    _event = null; 
    _handler = null; 
    _control = null; 
    _disposed = true; 
    } 
} 

然後使用它:

using (new EventInhibitor(textBox1, "TextChanged", textBox1_TextChanged)) 
{ 
    textBox1.Text = "Hello World"; 
} 
+0

在我發佈問題之前,我開始走下這條路,但我不喜歡用字符串指定事件。我從你的答案中得到了一個新想法,但可能只是將一個控件傳遞給該類,並禁用所有*事件。但另一方面,我需要存儲訂閱每個事件的所有事件處理程序,並且我不認爲這些信息在Control類之外是可用的嗎? – Anlo

0

作爲替代你想要的解決方案,這是我過去一直解決這個問題的方法。

TextBox myTextBox; 

private string _text; 
public string Text 
{ 
    get 
    { 
     return _text; 
    } 
    set 
    { 
     if (_text != value) 
     { 
      _text = value; 

      OnTextChanged(); 
     } 
    } 
} 

private void textBox_TextChanged(object sender, TextChangedEventArgs e) 
{ 
    if (Text != myTextBox.Text) 
    { 
     // the user must have edited the TextBox 
     Text = myTextBox.Text; 
    } 
} 

private void OnTextChanged() 
{ 
    if (myTextBox.Text != Text) 
     myTextBox.Text = Text; 
} 

這樣,當用戶通過在框中輸入來改變文本時,它會引發事件並執行您選擇的一些代碼。但是如果你手動設置Text屬性,它只會引發一次事件而不是兩次。如果您想對用戶編輯文本框時做出不同反應,那麼您可以在事件處理函數中添加一些額外的代碼,並且僅當文本因用戶輸入而更改時纔會執行。

通過這種方式,您可以取消關聯您想要處理文本更改的不同方面。例如,您可能想要執行OnTextChanged()中的代碼,該代碼會更新另一個控件,而不管Text是否因用戶操作或您的應用程序邏輯而發生更改。

3

又一解決方案..這只是調用函數之前和之後:

public class EventInhibitor : IDisposable { 
    private bool _disposed; 
    private Action _after; 

    public EventInhibitor(Action before, Action after) 
    { 
     before(); 
     _after = after; 
    } 

    public void Dispose() { 
     if (_disposed) 
      return; 

     _disposed = true; 
     _after(); 
    } 
} 

用法:

using(new EventInhibitor(() => textBox1.TextChanged -= textBox1_TextChanged, 
         () => textBox1.TextChanged += textBox1_TextChanged)) { 
} 
+0

比我希望的更詳細一點,但不是太糟糕... – Anlo

相關問題