Removing all event handlers in one go
Solution 1
You can use Delegate.RemoveAll()
. (The part you're interested in is in 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);
}
You should note that it doesn't alter the contents of the delegates you pass in to it, it returns an altered delegate. Consequently, you won't be able to alter the events on a button you've dropped on a form from the form, as button1.Click
can only have +=
or -=
used on it, not =
. This won't compile:
button1.Click = Delegate.RemoveAll(d, d) as EventHandler;
Also, be sure that wherever you're implementing this you're watching out for the potential of race conditions. You could end up with some really strange behavior if you're removing handlers from an event that is being called by another thread!
Solution 2
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: Apologies for my misunderstanding--I see that you were pretty clear about not having access to the event sources in your original post.
The simplest way I can think of to solve this problem involves implementing a Shared dictionary of object-to-document bindings. When an object enters a document, check the dictionary for an existing binding to another document; if present, remove handlers that refer to the old document before adding them for the new. Either way, update the dictionary with the new binding.
I think in most cases the performance and memory impacts would be negligible: unless you're dealing with many tens of thousands of small objects and frequently exchange them between documents, the memory overhead of each key/value pair and performance hit for each lookup operation should be fairly small.
As an alternative: if you can detect (in the document event handlers) that the sender of the event is no longer relevant to the document, you can detach the events there.
These seem like the kind of ideas you might have already rejected--but maybe not!
Solution 3
Use Delegate.RemoveAll
(maybe using reflection if the Delegate instance is private).
David Rutten
Bit-smith at Robert McNeel & Associates. Developer of the Grasshopper Algorithmic Modeling plug-in for the Rhinoceros 3D CAD application. I also keep a personal blog where not absolutely everything is about programming.
Updated on June 04, 2022Comments
-
David Rutten almost 2 years
Problem: I have a document class which contains a list of objects. These objects raise events such as
SolutionExpired
,DisplayExpired
etc. The document needs to respond to this.Documents can sometimes exchange objects, but a single object should never be 'part' of more than one document.
My document class contains a bunch of methods which serve as event handlers. Whenever an object enters the document, I use
AddHandler
to set up the events, and whenever an object is removed from the document I useRemoveHandler
to undo the damage. However, there are cases where it's difficult to make sure all the steps are properly taken and I might thus end up with rogue event handlers.Long story short; how do I remove all the handlers that are pointing to a specific method? Note, I don't have a list of potential event sources, these could be stored anywhere.
Something like:
RemoveHandler *.SolutionExpired, AddressOf DefObj_SolutionExpired
-
David Rutten almost 15 yearsBen, thanks for posting this. I'm afraid it's not making a lot of sense to me (or the VB compiler for that matter). Could you please post the original C#?
-
Ben M almost 15 yearsI knew I should have left the original C# version up. :-)
-
David Rutten over 14 yearsBecause I need to have an instance of the source for this. I think... I no longer have access to the event raising object, only the handler.
-
Ben M over 14 yearsI don't get how this is acceptable, given the OP's condition of needing to remove handlers from an event to which he doesn't have private-level access. I must be missing something!
-
user81993 about 8 yearsAlso this is C# while OP's question was about vb.net. While the two have a lot of overlap, event syntax is one where they greatly differ in