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;
  }
}
4

3 に答える 3

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)) {
}
于 2013-09-27T14:04:32.563 に答える
2

リフレクションを使用する必要があります ( import を忘れないでください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";
}
于 2013-09-27T13:34:57.197 に答える
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 プロパティを手動で設定すると、イベントは 2 回ではなく 1 回だけ発生します。ユーザーがテキストボックスを編集したときに別の反応をしたい場合は、イベントハンドラーに追加のコードを入れることができ、ユーザー入力のためにテキストが変更されたときにのみ実行されます。

このようにして、テキストの変更を処理する方法のさまざまな側面を切り離すことができます。たとえばOnTextChanged()、テキストがユーザー アクションまたはアプリ ロジックによって変更されたかどうかに関係なく、別のコントロールを更新するコードを実行したい場合があります。

于 2013-09-27T13:45:45.427 に答える