How can I unsubscribe to this .NET event? - c#

I wish to programatically unsubscribe to an event, which as been wired up.
I wish to know how I can unsubscribe to the EndRequest event.
I'm not to sure how to do this, considering i'm using inline code. (is that the correct technical term?)
I know i can use the some.Event -= MethodName to unsubscribe .. but I don't have a method name, here.
The reason I'm using the inline code is because I wish to reference a variable defined outside of the event (which I required .. but feels smelly... i feel like I need to pass it in).
Any suggestions?
Code time..
public void Init(HttpApplication httpApplication)
{
httpApplication.EndRequest += (sender, e) =>
{
if (some logic)
HandleCustomErrors(httpApplication, sender, e,
(HttpStatusCode)httpApplication.Response.StatusCode);
};
httpApplication.Error += (sender, e) =>
HandleCustomErrors(httpApplication, sender, e);
}
private static void HandleCustomErrors(HttpApplication httpApplication,
object sender, EventArgs e,
HttpStatusCode httpStatusCode =
HttpStatusCode.InternalServerError)
{ ... }
This is just some sample code I have, for me to handle errors in a ASP.NET application.
NOTE: Please don't turn this into a discussion about ASP.NET error handling. I'm just playing around with events and using these events for some sample R&D / learning.

It's not possible to unsubscribe that anonymous delegate. You would need to store it in a variable and unsubscribe it later:
EndRequestEventHandler handler = (sender, e) =>
{
if (some logic)
HandleCustomErrors(httpApplication, sender, e,
(HttpStatusCode)httpApplication.Response.StatusCode);
};
httpApplication.EndRequest += handler;
// do stuff
httpApplication.EndRequest -= handler;

Related

pass method to event handler in C# WPF

This works in adding an event handler in C# WPF
CheckBox ifPrint = new CheckBox();
ifPrint.AddHandler(CheckBox.ClickEvent, new RoutedEventHandler(
(sender, e) => //toggle check box event
{
//do stuff
}));
but it looks messy when the method body gets long, so I want to define the method elsewhere like this
ifPrint.AddHandler(CheckBox.ClickEvent, delegate(object sender, RoutedEventArgs e){
checkBoxClick(sender, e);
});
private void checkBoxClick(object sender, RoutedEventArgs e)
{
//do stuff
}
but this doesn't even compile with the error: Cannot convert anonymous type to type 'System.Delegate' because it is not a delegate type
Sorry, I am new to this and have no idea how it's supposed to be done. Is this even close? Thanks!
You can subscribe to a separate method like this, as long as the signature of checkBoxClick is correct:
ifPrint.Click += checkBoxClick;
You can also subscribe to an event inline like this:
ifPrint.Click += (s, e) => SomeMethod();
Which then allows you to name your method something more reasonable and not require it to accept parameters:
private void SomeMethod()
{
//do stuff
}
Just to explain it a little further, in the above code, s and e take the place of the parameters in your checkBoxClick event method, so it's basically equivalent to this:
ifPrint.Click += checkBoxClick;
private void checkBoxClick(object sender, RoutedEventArgs e)
{
SomeMethod();
}
Edit, in regards to your comment.
Given this is much simpler, when, if ever, should one use this? ifPrint.AddHandler(CheckBox.ClickEvent, new RoutedEventHandler( (sender, e) => { //do stuff }));
I honestly don't think I've ever used that syntax.
It seems that in most cases it does the same thing. According to the MSDN docs, there's a handledEventsToo parameter on the AddHandler() method, which I think could be significant.
Imagine you subscribed to an event multiple times, like this:
ifPrint.Click += checkBoxClick;
ifPrint.Click += checkBoxClick;
ifPrint.Click += checkBoxClick;
And inside your event, you set e.Handled = true. If you didn't have that line, you'd see the message box displayed 3 times. But with that line, you only get the message box once, because the first time the event fires, it marks the event "handled".
private void checkBoxClick(object sender, RoutedEventArgs e)
{
MessageBox.Show("Clicked!");
e.Handled = true;
}
By passing in true for the last parameter (it's false by default), you actually tell it to fire that event, even if other events already "handled" the event.
ifPrint.AddHandler(CheckBox.ClickEvent,
new RoutedEventHandler((s, e) => { /* do stuff */ }), true);
try this logic to attach click event handler for your checkbox.
CheckBox ifPrint = new CheckBox();
ifPrint.Click+=checkBoxClick;
private void checkBoxClick(object sender, RoutedEventArgs e)
{
//do stuff
}

describe the meaning of the shorthand notation of .net?("+=","=>")

The first one code is shorthand notation of second:
itemCountLines.Click = itemCountLines.Click + (sender, args) => countLines();
itemCountLines.Click += (sender, args) => CountLines();
But i did not understand what this expression is doing.Anybody Please Explain it to me
This code adds an handler to the Control.Click event:
public event EventHandler Click
where EventHandler is a delegate of type:
public delegate void EventHandler(
object sender,
EventArgs e
)
Normally, given you have a method with the same signature:
void SomeClickHandler(object sender, EventArgs e)
{
CountLines();
}
you would add this handler to handle Click event:
itemCountLines.Click += SomeClickHandler;
Operator += is possible because Click is an event, so you can add or remove a multiple EventHandlers to it. Simple speaking, after some control is clicked, you may want to make multiple actions (show some other control, log it to the database etc) so you are able to add multiple event handlers. You can even do itemCountLines.Click -= SomeClickHandler somewhere later to say, you do not want to handle Click with SomeClickHandler anymore.
But above code needs to define method SomeClickHandler which sometimes is unnecessary (for example, it is used only one in whole class). Then you can use anonymous delegate (added in C# 2.0):
itemCountLines.Click += delegate(object sender, EventArgs args)
{
CountLines();
};
but you can further shorten this syntax with lambda expression (added in C# 3.0) to:
itemCountLines.Click += (sender, args) => CountLines();
It simply add an event to the list of listeners itemCountLines.Click = itemCountLines.Click + (sender, args) so when an event occurs the instance of sender will be notified to raise the event inline => countLines(); as you are using lambda Expression => which will invoke countLines method
You're just attaching an event on Click, it is the same as saying
itemCountLines.Click += CountLines(sender, args);
Somewhere, there should be a method like this :
private void CountLines()
{
// Some Code There
}

Can I assign a method to multiple Form-based Events?

I'm constructing a Form and it has several numericUpDown controls, several checkbox controls and some text boxes etc. Each control has a event method (CheckedChanged, ValueChanged etc) that is triggered that does something but my main quesiton is this:
What I want to do is run a single method which will update a text field on my form but currently I have it just repeated 24 times. This works but I feel there must be a better way ... Below is an example of what I have so far.
private void button3_Click(object sender, EventArgs e)
{
// Code Specific to the Buton3_Click
UpdateTextLabel();
}
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
// Code Specific to the checkBox1_CheckChanged
UpdateTextLabel();
}
private void numericUpDown1_ValueChanged(object sender, EventArgs e)
{
// numericUpDown1 specific code ....
UpdateTextLabel();
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
// comboBox1 specific stuff ...
UpdateTextLabel();
}
// .... and so on for every method ....
Is there a better way to achieve this? I want to say "if any control is clicked or changed ... DO THIS "UpdateTextLabel()" thing " but not sure how to go about it. Happy to be directed to the answer as the questions I typed into search didn't seem to be the "right questions" ...
Thanks!
yes, any events of any controls can share the same event handler method as long as their event handler delegates are the same, in this case, the event handler delegates of those controls are all of type "EventHandler" (no return value and 2 arguments: object sender and EventArgs e).
private void UpdateTextLabel(object sender, EventArgs e)
{
//your original UpdateTextLabel code here
}
button3.Click += UpdateTextLabel;
checkBox1.CheckedChanged += UpdateTextLabel;
numericUpDown1.ValueChanged += UpdateTextLabel;
comboBox1.SelectedIndexChanged += UpdateTextLabel;
For sure! You can use lambdas to easily deal with the unused arguments:
button3.Click += (sender, args) => UpdateTextLabel();
checkBox1.CheckedChanged += (sender, args) => UpdateTextLabel();
numericUpDown1.ValueChanged += (sender, args) => UpdateTextLabel();
comboBox1.SelectedIndexChanged += (sender, args) => UpdateTextLabel();
Or as some developers are trending, if you don't care about the args, you can use underscores to "ignore" them for readability:
button3.Click += (_, __) => UpdateTextLabel();
checkBox1.CheckedChanged += (_, __) => UpdateTextLabel();
numericUpDown1.ValueChanged += (_, __) => UpdateTextLabel();
comboBox1.SelectedIndexChanged += (_, __) => UpdateTextLabel();
As the mighty Jon Skeet once schooled me, this is far superior to the default Visual Studio naming scheme of CONTROLNAME_EVENTNAME as you can easily read "when button 3 is clicked, update the text label", or "when the combobox is changed, update the text label". It also frees up your code file to eliminate a bunch of useless method wrappers. :)
EDIT: If you have it repeated 24 times, that seems a bit odd from a design standpoint. ... reads again Oh darn. I missed the comments, you want to run specific code as well as update the text box. Well, you could register more than one event:
button3.Click += (_, __) => SubmitForm();
button3.Click += (_, __) => UpdateTextLabel();
The problem with this, is technically, event listeners are not guaranteed to fire in-order. However, with this simple case (especially if you don't use -= and combine event handlers) you should be fine to maintain the order of execution. (I'm assuming you require UpdateTextLabel to fire after SubmitForm)
Or you can move the UpdateTextLabel call into your button handler:
button3.Click += (_, __) => SubmitForm();
private void SubmitForm(object sender, EventArgs e)
{
//do submission stuff
UpdateTextLabel();
}
Which kinda puts you into the same boat (albeit with better method naming). Perhaps instead you should move the UpdateTextLabel into a general "rebind" for your form:
button3.Click += (_, __) => SubmitForm();
private void SubmitForm(object sender, EventArgs e)
{
//do submission stuff
Rebind();
}
private void Rebind()
{
GatherInfo();
UpdateTextLabel();
UpdateTitles();
}
This way if you have to do additional work besides just updating a text label, all your code is calling a general Rebind (or whatever you want to call it) and it's easier to update.
EDITx2: I realized, another option is to use Aspect Oriented Programming. With something like PostSharp you can adorn methods to execute special code which gets compiled in. I'm 99% sure PostSharp allows you to attach to events (though I've never done that specifically):
button3.Click += (_, __) => SubmitForm();
[RebindForm]
private void SubmitForm(object sender, EventArgs e)
{
//do submission stuff
}
[Serializable]
public class RebindFormAttribute : OnMethodBoundaryAspect
{
public override void OnSuccess( MethodExecutionArgs args )
{
MyForm form = args.InstanceTarget as MyForm; //I actually forgot the "InstanceTarget" syntax off the top of my head, but something like that is there
if (form != null)
{
form.Rebind();
}
}
}
So even though we do not explicitly make a call anywhere to Rebind(), the attribute and Aspect Oriented Programming ends up running that extra code OnSuccess there whenever the method is invoked successfully.
Yes, you don't want to write code like this. You don't have to, the Application.Idle event is ideal to update UI state. It runs every time after Winforms retrieved all pending messages from the message queue. So is guaranteed to run after any of the events you currently subscribe. Make it look like this:
public Form1() {
InitializeComponent();
Application.Idle += UpdateTextLabel;
this.FormClosed += delegate { Application.Idle -= UpdateTextLabel; };
}
void UpdateTextLabel(object sender, EventArgs e) {
// etc..
}

How to wire up an EventHandler on a Winforms Application?

I have an application and I want to start a countdown timer.
I created an EventHandler under the partial class:
event EventHandler startTimer;
And I wrote a function:
public void startTimerEvent(object sender, EventArgs e)
{
this.Invoke((MethodInvoker)delegate
{
timer.Start();
});
}
How can I register this to the EventHandler and where do I wire it up in my form?
To tie the event to the handler:
startTimer += startTimerEvent;
But I'm not really sure there isn't a better way to go about solving your general problem. If you could describe further what you're after, perhaps we could suggest a better way.
So you need to choose an event that will trigger your handler. Let’s say you have a button, and you want to handle its click event. You could write:
myButton.Click += new EventHandler(StartWhatEver);
Then you would have your StartWhatEver that does what you want.
private void StartWhatEver(object sender, EventArgs e)
{
// Do stuff...
}
Note: If you are working in VS2010, you can type myButton.Click += (with space) then double tap the 'Tab' key and this will create your handler for you automatically including the triggered method.
Hope this helps.

Event fires more and more times

I have a silverlight mvvm application that loads main view with 2 user controls loaded into 2 ContentControls, one with listbox showing items and other with edit button. When i click edit button, 2 new user controls load into the ContentControls, one showing data to edit (EditData) and other having Save and Cancel button (EditAction).
When i click save button, it raises an event that is defined in seperate GlobalEvents.cs class like:
public event EventHandler OnSaveButtonClicked;
public void RaiseSaveButtonClicked()
{
this.OnSaveButtonClicked(this, EventArgs.Empty);
}
and i subscribe to it in the other user control EditData, because i need to transfer that edited data via custom EventArgs, so i have put in the constructor of it's ViewModel:
this.globalEvents.OnSaveButtonClicked += (s, e) => SaveData();
and in the Save data:
public void SaveData()
{
globalEvents.RaiseSaveData(EditedGuy);
}
which raises another event that loads previous user controls into their ControlContent and shows edited data in list box. Thats all fine, but whenever i click on edit and then save again, it raises the event twice, and again 3 times, then 4 and so on. How can i make it to be raised only ONE time? I thought it could be because every time i click edit, a new instance of the user control is loaded and i dont know, maybe the subscription to the event stays, so i have tried to paste
this.globalEvents.OnSaveButtonClicked -= (s, e) => SaveData();
to the Dispose() method but without success. How can i make this work?
You can't use lambdas when you want to unregister from events.
this.globalEvents.OnSaveButtonClicked += (s, e) => SaveData();
This will create one instance - let's call it instance A - of type EventHandler and add it as a handler.
this.globalEvents.OnSaveButtonClicked -= (s, e) => SaveData();
This will not remove instance A from the event but create a new instance - instance B - and tries to remove it from the event.
To fix this problem, either create a little method or save that anonymous method in a field:
class ViewModel
{
private EventHandler _saveButtonClickedHandler;
// ...
public ViewModel()
{
_saveButtonClickedHandler = (s, e) => SaveData();
this.globalEvents.OnSaveButtonClicked += _saveButtonClickedHandler;
// ...
}
public void Dispose()
{
this.globalEvents.OnSaveButtonClicked -= _saveButtonClickedHandler;
// ...
}
// ...
}
this.globalEvents.OnSaveButtonClicked += (s, e) => SaveData();
This line is being called multiple times so you are adding a new event handler every time.
You need to either move that line to somewhere where it's only called once or change the event handler to:
this.globalEvents.OnSaveButtonClicked += SaveData;
public void SaveData(object sender, EventArgs e)
{
globalEvents.RaiseSaveData(EditedGuy);
this.globalEvents.OnSaveButtonClicked -= SaveData();
}
So you remove the event handler after dealing with it. This assumes that the handler will be added back next time you go into edit mode.
You could define a private eventhandler delegate variable in your class and assign it in your constructor:
private SaveButtonClickedHandler _handler;
Assign the handler in your constructor:
_handler = (s,e) => SaveData();
this.globalEvents.OnSaveButtonClicked += _handler;
Dispose:
this.globalEvents.OnSaveButtonClicked -= _handler;
"SaveButtonClickedHandler" is pseudo-code/placeholder for whatever the name of the delegate should be.
Hasanain
You'll have to put in a proper event handler method that calls SaveData() and register/unregister that. Otherwise you try to unregister another "new" anonymous method instead of the original one you've registered, which you, because it is anonymous, cannot actually access anymore.
public void SaveButtonClicked(object sender, EventArgs e)
{
SaveData();
}
this.globalEvents.OnSaveButtonClicked += SaveButtonClicked;
this.globalEvents.OnSaveButtonClicked -= SaveButtonClicked;

Categories

Resources