暂时取消订阅活动的简洁解决方案

本文关键字:简洁 解决方案 活动 取消 | 更新日期: 2023-09-27 18:32:59

我正在寻找一个简洁的解决方案来暂时取消订阅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;
  }
}

暂时取消订阅活动的简洁解决方案

另一种解决方案...只是在之前和之后调用函数:

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)) {
}
你必须

使用反射(所以不要忘记导入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";
}

作为您想要的解决方案的替代方案,这就是我过去一直解决这个问题的方式。

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() 中执行代码,无论文本是否因用户操作或应用逻辑而更改,都会更新另一个控件。