2009-07-19 21 views
5

問題:オブジェクトのリストを含むドキュメントクラスがあります。これらのオブジェクトは、SolutionExpired,DisplayExpiredなどのイベントを発生させます。ドキュメントは、これに応答する必要があります。一度にすべてのイベントハンドラを削除する

ドキュメントはオブジェクトを交換することがありますが、1つのオブジェクトが複数のドキュメントの「一部」になることはありません。

私のドキュメントクラスには、イベントハンドラとして機能する一連のメソッドが含まれています。オブジェクトがドキュメントに入力されるたびに、私はAddHandlerを使用してイベントを設定し、オブジェクトがドキュメントから削除されるたびにRemoveHandlerを使用してダメージを元に戻します。しかし、すべてのステップが適切に行われているかどうかを確認することが難しく、不正なイベントハンドラになる可能性がある場合があります。

ロングストーリーショート;特定のメソッドを指しているハンドラーをすべて削除するにはどうすればよいですか?注目すべきイベントソースのリストはありません。どこにでも保存できます。

のような何か:

RemoveHandler *.SolutionExpired, AddressOf DefObj_SolutionExpired 
+0

[コントロールからすべてのイベントハンドラを削除する方法](http://stackoverflow.com/questions/91778/how-to-remove-all-event-handlers-from-a-control) – ChrisF

+0

可能[コントロールからすべてのイベントハンドラを削除する方法]の複製(https://stackoverflow.com/questions/91778/how-to-remove-all-event-handlers-from-a-control) –

答えて

5

Delegate.RemoveAll()を使用できます。 (あなたが興味を持っている部分がbutton2_Clickである)

public void Form_Load(object sender, EventArgs e) 
{ 
    button1.Click += new EventHandler(button1_Click); 
    button1.Click += new EventHandler(button1_Click); 
    button2.Click += new EventHandler(button2_Click); 
    TestEvent += new EventHandler(Form_TestEvent); 
} 
event EventHandler TestEvent; 
void OnTestEvent(EventArgs e) 
{ 
    if (TestEvent != null) 
     TestEvent(this, e); 
} 
void Form_TestEvent(object sender, EventArgs e) 
{ 
    MessageBox.Show("TestEvent fired"); 
} 
void button2_Click(object sender, EventArgs e) 
{ 
    Delegate d = TestEvent as Delegate; 
    TestEvent = Delegate.RemoveAll(d, d) as EventHandler; 
} 
void button1_Click(object sender, EventArgs e) 
{ 
    OnTestEvent(EventArgs.Empty); 
} 

あなたはそれはあなたがそれに渡すデリゲートの内容を変更しない、それが変更されたデリゲートを返すことに注意してください。したがって、フォームからフォームにドロップしたボタンのイベントを変更することはできません.button1.Click+=または-=しか使用できません。=ではありません。また、

button1.Click = Delegate.RemoveAll(d, d) as EventHandler; 

をあなたがこれを実装しようとしているところはどこでもあなたが競合条件の可能性のために監視していますことを確認してください。これはコンパイルされません。別のスレッドから呼び出されているイベントからハンドラを削除していると、本当に奇妙な振る舞いで終わることがあります。

+4

私は、彼が私的レベルのアクセス権を持っていないイベントからハンドラを削除する必要があるOPの条件を考えれば、これがどのように受け入れられるかはわかりません。私は何かが欠けているに違いない! –

+1

これはC#ですが、OPの質問はvb.netに関するものです。 2つは重複していますが、イベントの構文は大きく異なります – user81993

1
public class TheAnswer 
{ 
    public event EventHandler MyEvent = delegate { }; 

    public void RemoveFromMyEvent(string methodName) 
    { 
     foreach (var handler in MyEvent.GetInvocationList()) 
     { 
      if (handler.Method.Name == methodName) 
      { 
       MyEvent -= (EventHandler)handler; 
      } 
     } 
    } 
} 

EDIT 2:私の誤解のため謝罪 - 私はあなたがあなたのオリジナルのポストにイベント・ソースへのアクセスを持っていないについてかなり明確だったことがわかります。

私がこの問題を解決するために考える最も簡単な方法は、オブジェクト間のバインディングの共有辞書を実装することです。オブジェクトがドキュメントに入ると、別のドキュメントへの既存のバインディングを辞書でチェックします。存在する場合は、古いドキュメントを参照するハンドラを削除してから新しいドキュメントに追加します。どちらの方法でも、新しいバインディングで辞書を更新してください。

多くの場合、パフォーマンスとメモリへの影響は無視できるものです。何千もの小さなオブジェクトを扱い、ドキュメント間で頻繁に交換しない限り、各キーと値のペアのメモリオーバーヘッドとパフォーマンスヒットそれぞれのルックアップ操作がかなり小さいはずです。

代わりに、(ドキュメントのイベントハンドラで)イベントの送信者がもはやドキュメントに関連していないことを検出できる場合は、そこのイベントを切り離すことができます。

これはあなたがすでに拒否しているかもしれないアイデアのようですが、そうではないかもしれません!

+0

ベン、投稿していただきありがとうございますこの。私はそれが私(またはその問題についてはVBのコンパイラ)に多くの意味を作っていないことが怖いです。元のC#を投稿してください。 –

+1

私は元のC#バージョンを残しておくべきであることを知っていました。 :-) –

+0

おかげでベン、私はあなたがここで何をしているのか見ていますが、私が間違っていなければ、この関数はイベントを起こしているインスタンスへの参照があると仮定しています。これらのオブジェクトは、地平線上のどこかの別のリストに消えてから長いかもしれません。 ハンドラを定義するクラスではなく、イベントを発生させるクラスでハンドラデリゲートが定義されているため、おそらくこれを行うことができないと考え始めています。 –

1

Delegate.RemoveAllを使用してください(多分、Delegateインスタンスがプライベートである場合はリフレクションを使用してください)。

+0

私はこれのためのソースのインスタンスを持っている必要があるので。 私はもはや、オブジェクトを呼び出すイベントにアクセスすることはできません。ハンドラのみです。 –

関連する問題