Can you tell me which is the best way to create an event or all the options are good?
// OPTION 1
buttonAlert.Click += delegate
{
textChange.Text = string.Format("Hello World");
};
// OPTION 2
buttonAlert.Click +=(sender, e) =>
{
textChange.Text = string.Format("Hello World");
};
// OPTION 3
buttonAlert.Click += delegate (object sender, EventArgs e)
{
textChange.Text = string.Format("Hello World");
};
Its just a matter of preference. In terms of performance are all equivalent.
So, choose based on what you need and prefer.
As a complement of my answer i like to alert that you must unsubscribe a event (-=) after subscrive (+=).
From the documentation:
To prevent your event handler from being invoked when the event is
raised, simply unsubscribe from the event. In order to prevent
resource leaks, it is important to unsubscribe from events before you
dispose of a subscriber object. Until you unsubscribe from an event,
the multicast delegate that underlies the event in the publishing
object has a reference to the delegate that encapsulates the
subscriber's event handler. As long as the publishing object holds
that reference, your subscriber object will not be garbage collected.
I would say that first option is the best when you don´t need the lambda parameters (sender, event).
Between second and third I would choose second because it´s cleaner (just a matter of preference.
You can also use a method as a delegate, and it´s probably the best if you want to manage memory correctly. When you use a delegate or lambda there is no way to unsubscribe. That means that even if you destroy or leave the activity/fragment, the object will remain in memory and the garbage collector won´t be able to clear it. In the case the user opens and closes this screen many times, you may get an OutOfMemoryException eventually. This happens very often in Android. This would be the solution:
protected override void OnResume()
{
base.OnResume();
buttonAlert.Click += OnButtonClick;
}
protected override void OnPause()
{
base.OnPause();
buttonAlert.Click -= OnButtonClick;
}
private void OnButtonClick(object sender, EventArgs e)
{
textChange.Text = string.Format("Hello World");
}
Related
I am learning Xamarin Android, and I see a lot of official samples using lambdas to subscribe Click events. Something like: mButton.Click += (sender, args) => { ... } is very common. I think this pattern, using lambda, cannot unsubscribe the event.(Correct me if I am wrong :) )
Today I read this document: Cross-Platform Performance - Unsubscribe from Events. It says that we should unsubscribe events to prevent memory leaks.
Then I am confused. Should I unsubscribe all the Click events? I feel that since the mButton is a member of my Activity, when destroying my Activity, the mButton should also be destroyed and therefore it is not necessary to unsubscribe its Click event. Is is true? If so, then in what cases should I unsubscribe a event?
Thanks!
I would say it depends. As long there there are no references kept and the garbage collector can do his job, you don't have to. But otherwise it is good practice to do so to prevent memory leaks. So I prefer doing this.
To unsibscribe lambda events, just store it in a variable or field
EventHandler buttonOnClick = (sender, args) => button.Text = string.Format("{0} clicks!", count++);
button.Click += buttonOnClick;
button.Click -= buttonOnClick;
This is how I generally do it
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
// Set our view from the "main" layout resource
SetContentView (Resource.Layout.LoginPage);
InflateViews ();
}
protected override void OnResume ()
{
base.OnResume ();
BindHandlers ();
}
protected override void OnPause ()
{
base.OnPause ();
UnBindHandlers ();
}
void InflateViews()
{
loginButton = FindViewById (Resource.Id.loginButton);
usernameField = FindViewById<EditText> (Resource.Id.userName);
passwordField = FindViewById<EditText> (Resource.Id.password);
forgotPassword = FindViewById (Resource.Id.forgotPassword);
}
void BindHandlers()
{
loginButton.Click+= LoginButton_Click;
forgotPassword.Click+= ForgotPassword_Click;
}
void ForgotPassword_Click (object sender, EventArgs e)
{
StartActivity (typeof(ForgotPasswordActivity));
}
void UnBindHandlers()
{
loginButton.Click-= LoginButton_Click;
forgotPassword.Click-= ForgotPassword_Click;
}
Absolutely yes!
To prevent memory leaks it is important to prevent cycling references and such. Take your time and search on SO and you will find a lot about this topic.
I have a ton on controls on a form, and there is a specific time when I want to stop all of my events from being handled for the time being. Usually I just do something like this if I don't want certain events handled:
private bool myOpRunning = false;
private void OpFunction()
{
myOpRunning = true;
// do stuff
myOpRunning = false;
}
private void someHandler(object sender, EventArgs e)
{
if (myOpRunning) return;
// otherwise, do things
}
But I have A LOT of handlers I need to update. Just curious if .NET has a quicker way than having to update each handler method.
You will have to create your own mechanism to do this. It's not too bad though. Consider adding another layer of abstraction. For example, a simple class called FilteredEventHandler that checks the state of myOpRunning and either calls the real event handler, or suppresses the event. The class would look something like this:
public sealed class FilteredEventHandler
{
private readonly Func<bool> supressEvent;
private readonly EventHandler realEvent;
public FilteredEventHandler(Func<bool> supressEvent, EventHandler eventToRaise)
{
this.supressEvent = supressEvent;
this.realEvent = eventToRaise;
}
//Checks the "supress" flag and either call the real event handler, or skip it
public void FakeEventHandler(object sender, EventArgs e)
{
if (!this.supressEvent())
{
this.realEvent(sender, e);
}
}
}
Then when you hook up the event, do this:
this.Control.WhateverEvent += new FilteredEventHandler(() => myOpRunning, RealEventHandler).FakeEventHandler;
When WhateverEvent gets raised, it will call the FilteredEventHandler.FakeEventHandler method. That method will check the flag and either call, or not call the real event handler. This is pretty much logically the same as what you're already doing, but the code that checks the myOpRunning flag is in only one place instead of sprinkled all over your code.
Edit to answer question in the comments:
Now, this example is a bit incomplete. It's a little difficult to unsubscribe from the event completely because you lose the reference to the FilteredEventHandler that's hooked up. For example, you can't do:
this.Control.WhateverEvent += new FilteredEventHandler(() => myOpRunning, RealEventHandler).FakeEventHandler;
//Some other stuff. . .
this.Control.WhateverEvent -= new FilteredEventHandler(() => myOpRunning, RealEventHandler).FakeEventHandler; //Not gonna work!
because you're hooking up one delegate and unhooking a completely different one! Granted, both delegates are the FakeEventHandler method, but that's an instance method and they belong to two completely different FilteredEventHandler objects.
Somehow, you need to get a reference to the first FilteredEventHandler that you constructed in order to unhook. Something like this would work, but it involves keeping track of a bunch of FilteredEventHandler objects which is probably no better than the original problem you're trying to solve:
FilteredEventHandler filter1 = new FilteredEventHandler(() => myOpRunning, RealEventHandler);
this.Control.WhateverEvent += filter1.FakeEventHandler;
//Code that does other stuff. . .
this.Control.WhateverEvent -= filter1.FakeEventHandler;
What I would do, in this case, is to have the FilteredEventHandler.FakeEventHandler method pass its 'this' reference to the RealEventHandler. This involves changing the signature of the RealEventHandler to either take another parameter:
public void RealEventHandler(object sender, EventArgs e, FilteredEventHandler filter);
or changing it to take an EventArgs subclass that you create that holds a reference to the FilteredEventHandler. This is the better way to do it
public void RealEventHandler(object sender, FilteredEventArgs e);
//Also change the signature of the FilteredEventHandler constructor:
public FilteredEventHandler(Func<bool> supressEvent, EventHandler<FilteredEventArgs> eventToRaise)
{
//. . .
}
//Finally, change the FakeEventHandler method to call the real event and pass a reference to itself
this.realEvent(sender, new FilteredEventArgs(e, this)); //Pass the original event args + a reference to this specific FilteredEventHandler
Now the RealEventHandler that gets called can unsubscribe itself because it has a reference to the correct FilteredEventHandler object that got passed in to its parameters.
My final advice, though is to not do any of this! Neolisk nailed it in the comments. Doing something complicated like this is a sign that there's a problem with the design. It will be difficult for anybody who needs to maintain this code in the future (even you, suprisingly!) to figure out the non-standard plumbing involved.
Usually when you're subscribing to events, you do it once and forget it - especially in a GUI program.
You can do it with reflection ...
public static void UnregisterAllEvents(object objectWithEvents)
{
Type theType = objectWithEvents.GetType();
//Even though the events are public, the FieldInfo associated with them is private
foreach (System.Reflection.FieldInfo field in theType.GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance))
{
//eventInfo will be null if this is a normal field and not an event.
System.Reflection.EventInfo eventInfo = theType.GetEvent(field.Name);
if (eventInfo != null)
{
MulticastDelegate multicastDelegate = field.GetValue(objectWithEvents) as MulticastDelegate;
if (multicastDelegate != null)
{
foreach (Delegate _delegate in multicastDelegate.GetInvocationList())
{
eventInfo.RemoveEventHandler(objectWithEvents, _delegate);
}
}
}
}
}
You could just disable the container where all these controls are put in. For example, if you put them in a GroupBox or Panel simply use: groupbox.Enabled = false; or panel.Enabled = false;. You could also disable the form From1.Enabled = false; and show a wait cursor. You can still copy and paste these controls in a container other than the form.
What's the benefits of registering an event as:
void MyMethod()
{
button1.Click += delegate (object sender, EventArgs e)
{
..
}
}
in comparison with:
void MyMethod()
{
button1.Click += new System.EventHandler(this.button1_Click);
}
void button1_Click(object sender, EventArgs e)
{
..
}
UPDATE:
And what about unsubscribing it?
The benefit is that you don't have to come up with a name and a place in your class.
For a light function, tightly coupled to the code that register the event, the short version is more convenient.
Note that you can also exchange delegate for a =>
button1.Click += (object sender, EventArgs e) =>
{
..
}
You can be even more concise:
button1.Click += ( sender, e ) =>
{
};
Syntactically it's cleaner (as long as it doesn't lead to long blocks of code which would be better broken up into named methods).
The inline declaration is a closure, which gives you access to the variables adjacent to the anonymous method.
From: What are 'closures' in .NET?
In essence, a closure is a block of code which can be executed at a
later time, but which maintains the environment in which it was first
created - i.e. it can still use the local variables etc of the method
which created it, even after that method has finished executing.
See also: http://csharpindepth.com/articles/chapter5/closures.aspx
When registering event handler with an anonymous delegate or lambda, you can write shorter code and use closures. But you cannot unsubscribe from the event, and if the event handler code is too long, your code becomes ugly.
It's just about coding style.
Worth mantioning that declaring it like in first case let you to avoid "spaghetti code" and inject into the handler function local variables (if needed) in more natural(human readable way).
To be more clear. By writing like in first case you can:
int x = 0;
System.Windows.Forms.Button button = new System.Windows.Forms.Button();
button.Click += (o,e)=> {
++x;
};
Inside the event handler you can access the local variable declared actually out for the scope of the handler method. For most people it seems "natural", but if you think like a developer it shouldn't be even possible.
Good luck.
How can the event System.ComponentModel.CancelEventArgs be used? Suppose we have the following code:
public event CancelEventHandler EventTest = delegate { };
public void MakeSomethingThatRaisesEvent()
{
CancelEventArgs cea = new CancelEventArgs();
EventTest(this, cea);
if (cea.Cancel)
{
// Do something
}
else
{
// Do something else
}
}
What happens if more than one delegate is registered on the event? There is any way to get the results of all the subscribers?
This is used on Winforms (at least) sometimes. If not possible to get all values, they suppose only one subscriber to the event?
To ask each subscriber separately, you need to access the list:
foreach (CancelEventHandler subHandler in handler.GetInvocationList())
{
// treat individually
}
Then you can check each in turn; otherwise you just get the final vote.
Normally, in most cases, the class just allows multiple subscribers, but each gets the same instance of CancelEventArgs.
If any of the subscribers set Cancel to true, the operation will be treated as canceled.
You can work around this by getting the invocation list, and sending an event to each subscriber, but this is not usually necessary.
For example, I have a base event publishing method:
protected virtual OnSomeEvent(EventArgs e)
{
var handler = SomeEvent;
if (handler != null)
{
handler(this, e);
// handler(this, new EventArgs());// EDIT: Yes it should be
// handler(this, e),
// ignore this one :D
}
}
For a derived class that overrides OnSomeEvent and raises an additional event when it fires:
protected override OnSomeEvent(EventArgs e)
{
base.OnSomeEvent(e);
if (ExtendedEvent != null)
{
OnExtendedEvent(e);
}
}
protected void OnExtendedEvent(EventArgs e)
{
// some stuff done
// new information the ExtendedEventArgs object needs
// is not available until this point
ExtendedEvent(this, new ExtendedEventArgs(someStuff, someOtherStuff));
}
And if derivation goes on like this, it will create a new derived EventArgs for each generation of derived class that requires it. However it seems various derivations of EventArgs on the .NET framework are not designed to be mutable (no setters), this discourages an object from keeping a single instance of EventArgs and modify it as it goes.
So every time an event like this fires, it will re-allocate memory for all involved EventArgs objects. In a graphic intense application where an event can be triggered dozens of times per second (such as OnPaint event on a control), is this really a good practice?
Should I make some changes to OnExtendedEvent() and make ExtendedEventArgs mutable so the following is possible?
protected ExtendedEventArgs extendedArgs = ExtendedEventArgs.Empty;
protected void OnExtendedEvent(EventArgs e)
{
// some stuff done
// new information the ExtendedEventArgs object needs
// is not available until this point
extendedArgs.someProperty1 = someStuff;
extendedArgs.someProperty2 = someOtherStuff;
ExtendedEvent(this, extendedArgs);
}
EDIT: Fixed the example code, should be clearer now.
First off, why take an EventArgs argument to your firing method if you are just ignoring it anyway? That is the real waste, but the resource consumption is less problematic than the lie that your method is telling its callers. Just pass the argument on through, your firing method likely will not have relevant info accessible to create the EventArgs object anyway:
protected virtual OnSomeEvent(EventArgs e)
{
var handler = SomeEvent;
if (handler != null)
{
handler(this, e);
}
}
So, now that we have that straight, if your EventArgs object has no meaningful information to tell your subscribers, just use EventArgs.Empty, that's what it is there for. You could follow the same pattern for your custom EventArgs classes, but honestly, you are worrying about nothing. Creating EventArgs objects will never be a bottleneck in your application, and if it is, you have design problems.
I would create a new immutable object each time it is fired, as there are values in the event arguments.
The main reason is the what would happen if a new event is fired again while an existing event is being handled?
This will possibly happen in multi-threaded applications but may even happen on a single thread as shown by the following example:
First event is fired with the following values:
extendedArgs.someProperty1 = "Fire 1";
extendedArgs.someProperty2 = "Fire 1 Other Stuff";
Then somehow the first event handler does something causes the event to be fired again with the following arguments:
extendedArgs.someProperty1 = "Fire 2";
extendedArgs.someProperty2 = "Fire 2 Other Stuff";
All the event handlers are for the second event are processed, and now we are back to processing the rest of the event handlers for the first event.
Now since the same object is used all the event handlers for the first event will now be have "Fire 2" as their someProperty1, as the second event overwrote the values.
As #nobugz mentioned don't be afraid to create short-lived garbage.
I'm a little confused by your OnExtendedEvent code - are you meaning to redispatch the event as a SomeEvent?
When a client adds an event handler, they expect they are able to remove the event handler while handling the event, like this:
someObject.SomeEvent += OnSomeEvent;
// ...
private void OnSomeEvent(object sender, EventArgs e)
{
someObject.SomeEvent -= OnSomeEvent;
}
If you do not follow the standard dispatching practice, this code will throw an Exception very much to the surprise of the person using your code.