I want to conditionally unhook an event handler. Is this the right way to do it:
tb.TextChanged -= textBoxIntName_TextChanged;
?
This seems to be sensible, as hooking it up required:
tb.TextChanged += textBoxIntName_TextChanged;
...but it also seems that what corresponds to the "Delphi way" makes as much or more sense (but alas, it does not compile):
tb.TextChanged = nil;
You cannot assign events - only attach (+=) and remove (-=) operations are available for clients.
Read more about events here.
Also C# specification says:
Since += and -= are the only operations that are permitted on an event
outside the type that declares the event, external code can add and
remove handlers for an event, but cannot in any other way obtain or
modify the underlying list of event handlers.
Related
I have an event handler that for some reason (I don't understand) get called twice, I thought that setting e.Handled = true will solve it but it doesn't, finally I unsubscribed from the event inside the handler, and it works:
((FabTabItem)sender).TabClosing -= oTab_TabClosing;
So I have these questions:
What is the difference between the both approches, Don't they stop handling the event?
Is it OK to unsubscribe from the event inside its handler since its natural to say "stop listening to the event after it's been handled"? (I don't see this a lot)
From the following MSDN page on the KeyPressEventArgs.Handled Property:
If the event is not handled, it will be sent to the operating system for default processing.
So setting it to true means that any further processing of the event will not happen for the rest of that call to the event depending on how the other events handle the Handled property. As #Enigmativity put it in the comments to the OP:
When you have several handlers for the one event they are called in series. If one of the handlers thinks that it has "handled" the event and no further handlers need to do anything it can set e.Handled = true. It is up to the subsequent handlers to honour this flag and not do any processing - but they are still called. Also this doesn't change the handling for when the next time the event is raised - all of the handlers get called again.
By unsubscribing from the event the rest of the actions in the event still occur, in the case of the above mentioned event it still goes through to the operating system.
The two scenarios you described are not exactly the same.
Unsubscribing from the event inside the handler itself is fine, all it does is remove the call to that handler next time the event is raised.
With that said if you are doing this because the event is being called more times than it should be you should probably track down where the event is being subscribed too. It is likely you have accidentally subscribed the same handler twice and that is the proper fix rather than hacking around it by unsubscribing from the event.
What is the difference between the both approaches, Don't they sop handling the event?
e.Handled = true; indicates that the event handler has already processed the event and dealt with it, so it doesn't need to be processed any further. In other words, please don't take any further action.
but the second will Remove Event and Don,t happen next time
Is it OK to unsubscribe from the event inside its handler since its natural to say "stop listening to the event after it's been handled"? (I don't see this a lot)
its depend to your Roll if you want not happen after a If use handle but if you want never happen after if use second
and remove event
Often in code I see a line of code, I have an idea it do something about event but not clearly know what it does.
Is it possible that I can attach form A's load event in Form B with this, or what is its benefit?
this.CGForm .Load +=new EventHandler(CGForm_Load);
Yes, it clearly has to do with events.
.Load in this case the the Form.Load event. The += operator adds one event handler to the event. An event can have many event handlers at the same time. Event handlers are just regular method that can be anywhere in your code base. When the event fires all subscribed methods will be called, one after the other.
I see no particular good reason to have FormA listen to the Load event of FormB, but other events might be more interesting, like the Form.Closed event. This is a way to have FormA react to changes in FormB.
Edit
Note that this causes FormA to hold a reference to FormB and FormB won't be garbage collected until FormA releases the reference to FormB (with
this.CGForm .Load -=new EventHandler(CGForm_Load);, note the -=) this is a common cause for memory leaks in .NET.
Subscribing to events from other forms is a "code smell" that can be a potential structure problem with your code. In some cases it is required, but if you have it all over the place your code will be hard to understand and maintain.
What this line means is that you subscribe the method CGForm_Load() to the this.CGForm.Load event. The method CGForm_Load() is the event handler or the callback.
After you run this line, every time the event is raised (in this case - every time the form is loaded), CGForm_Load() will be called automatically.
In order to unsubscribe a callback, use -= like this:
this.CGForm.Load -= new EventHandler(CGForm_Load)
Once an event callback is unsubscribed, the next time the event is raised (if the form is loaded again) the callback will no longer be called.
I find the following metaphor helpful: An event is like a power outlet, and callbacks are like power plugs. Subscribing is like connecting the plug to the outlet, and unsubscribing is like pulling it out. While there is a connection, all invocations of the event trigger the callback.
It simply adds the GCForm_Load method to the Load event on the CGForm. Under the hood when the CGForm is loaded code like the following will execute. Whenever this happens all event subscribers (in this case the method being subscribed here as CGForm_Load) will be invoked.
<pseudocode>
class CGForm
{
public EventHandler<FormLoadedEventArgs> Load;
private void SomeMethodThatLoadsTheForm()
{
LoadForm();
var loadHandlers = Load;
if (loadHandlers != null)
{
loadHandlers(new FormLoadedEventArgs(...));
}
}
}
</pseudocode>
this.CGForm .Load +=new EventHandler(CGForm_Load); subscribes the event handler delegate CGForm_Load to the Load event of the CGForm object.
Documentation about subscribing to events can be found at http://msdn.microsoft.com/en-us/library/ms366768(v=vs.80).aspx .
And index of information about how events work in .NET can be found at http://msdn.microsoft.com/en-US/library/awbftdfh(v=VS.80).aspx
I would like to know if I bind the TextChanged event handler to a TextBox control, then how can I ensure that won't be allowed to bind this event handler again?
You can't ensure that. You would theoretically be allowed to bind the same event handler to a textbox (or other control) more than once. The only thing that events allow you to do is add a handler and remove a handler—there's no additional means provided to check for existing subscribers. If you don't believe me, Jon Skeet provides the authoritative answer here, and in his article on events.
If you need to ensure that you don't accidentally subscribe a control to the same event twice, you'll need to keep track of it yourself. Honestly, you should never end up in a situation where you don't know what event handlers are subscribed. Not only does this reflect sloppy design, but it probably also means that you aren't taking care to remove your event handlers when they are no longer necessary.
A possible solution is provided in the answers to this question, but I caution you from using something like this blindly. As others have argued, this code is something of an anti-pattern.
You can bind it programatically as many times as you'd like. If you want to prevent this you can use a List<object> to keep references in, for example:
private List gotRefs = new List();
public void MyMethod()
{
if (!gotRefs.Contains(txtTextBox1)) {
txtTextBox1.TextChanged += txtTextBox1_TextChanged;
gotRefs.Add(txtTextBox1);
}
}
You can actually use a hack.
You can make textbox private to your class to ensure, that only your single class is able to access the text box and add handlers to it.
private TextBox txtChanging;
Then, in your class, you can create a custom event like textBoxTextChanged
public event Action TextBoxTextChanged;
Create a standart method OnTextBoxTextChanged
private OnTextBoxChanged( object sender, EventArgs args )
{
if( TextBoxTextChanged != null )
TextBoxTextChanged();
}
Bind this OnTextBoxChangedMethod to TextChanged event of the TextBox
txtChanging.TextChanged += OnTextBoxChanged;
Ensure that NO OTHER METHOD is bound to TextChanged event of the text box
Bound all your main payload text changed handlers to your new custom event instead of text box textchanged event directly
TextBoxTextChanged += txtChanged_TextChnaged;
All that paperwork is because events actually provide a lot of information, but only to the methods inside the class where they are defined.
You can check bound delegates with
TextBoxTextChanged.GetInvocationList()
and their count with
TextBoxTextChanged.GetInvocationList().Count() //(C# 4.0/LINQ)
or just count them through foreach.
i am using textchanged event and i disable it where i don't need as following
object.Event -= new System.EventHandler(myHandler);
//my code which doesn't need event handler
object.Event += new System.EventHandler(myHandler);
i used many times like this. but i needed sometimes 2 disable code like this:
object.Event -= new System.EventHandler(myHandler);
object.Event -= new System.EventHandler(myHandler);
of course i finished it with 2 enable code
object.Event += new System.EventHandler(myHandler);
object.Event += new System.EventHandler(myHandler);
i don't know yet why i needed 2 times remove event handler but it worked great.
but in 1 case i got problem.
it doesn't work with 2 or more disable code.
my question is, how can i watch this eventhandler if it needs just one -= code or more?
or how can i manage it?
i always worked like this, to make sure that i always leave event handler as first time
object.Event -= new System.EventHandler(myHandler);
//my code which doesn't need event handler
object.Event += new System.EventHandler(myHandler);
My advice would be to stop removing and re-adding the event handler, and instead add a flag to your event handler itself which inhibits whatever activities you need to inhibit during these sections of code.
You can either have a single boolean flag, or use some kind of reference count, depending on how you need to cope with nesting.
If there's some reason why you can't change the existing event handler, what about creating a new event hander which you attach to Event, and call the old one from that?
You need to remove an event handler as many times as you've added it - and you won't be able to tell when that is, as the subscriptions are effectively hidden from you.
Ideally, just make sure you only subscribe as many times as you need to, and it should be obvious how many times you need to unsubscribe too. Usually this will be once. It's somewhat odd that you ended up with two subscriptions to start with... I suspect that may indicate a bug somewhere in your code.
Note that unsubscribing using an event handler which isn't already subscribed is a no-op.
(Will's idea of the event handler itself knowing whether or not it's really "active" is a good one too, btw.)
I was wondering if setting an object to null will clean up any eventhandlers that are attached to the objects events...
e.g.
Button button = new Button();
button.Click += new EventHandler(Button_Click);
button = null;
button = new Button();
button.Click += new EventHandler(Button_Click);
button = null;
etc...
Will this cause a memory leak?
If there are no other references to button anywhere, then there is no need to remove the event handler here to avoid a memory leak. Event handlers are one-way references, so removing them is only needed when the object with events is long-lived, and you want to avoid the handlers (i.e. objects with handler methods) from living longer than they should. In your example, this isn't the case.
Summary: You need to explicitly unsubscribe when the event source/publisher is long-lived and the subscribers are not. If the event source out-lives the subscribers, all registered subscribers are kept "alive" by the event source (not collected by the GC) unless they unsubscribe (and remove the reference to themselves from the event publisher's notification list)
Also this is a duplicate of
Is it necessary to explicitly remove event handlers in C# and has a good title n answer. So voting to close.
See the discussion here under "The final question: do we have to remove event handlers?"
Conclusion: you should remove
delegates from events when they reach
outside the class itself; i.e. when
you subscribe to external events, you
should end your subscription when you
are done. Failing to do so will keep
your object alive longer than
necessary.