pass method to event handler in C# WPF - c#

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
}

Related

How to make the condition to be a Eventhandler Control.click event?

Basically what I am trying to do is, creating a new method that will have an event handler button click event condition within it.enter code here
//when this event is active the only should then should run what inside the {}
if(buttonEvents_Click(object sender, EventArgs e))
{enter code here`
//Happening something
}
what I already tried withing(buttonEvents.click) get the error "the event control.click can only appear on the left side =+ or -+".
You should have your event handler method like you always do:
buttonEvents_Click(object sender, EventArgs e)
{
if(condition){ //you need your condition checker inside the method
//... coder here
}
}
now for any control that you want to add this handler you can sompliy do:
myButton.Click += buttonEvents_Click;
Alternatively you can do this like:
myButton.Click += (s, e) =>
{
//which s is the sender and e is the EventArgs
//code here
};

Is += delegate {} the correct way to attach custom eventargs to a UI control event?

I have been tinkering with Events to gain a better understanding of their use in very general situations. I'm surprised to find the following, so I'm probably heading in the wrong direction...the essence of what I'm doing is changing a button to a random color when it is clicked:
Windows Form
public Form1()
{
ColorChanges KK = new ColorChanges();
KK.ColorEventHandler += handle_ColorChanges;
button1.Click += delegate { KK.ChangeColor(button1); };
}
Event Class
class ColorChanges
{
*... properties & constructor*
public void ChangeColor(object sender)
{
*... randomly assign color to ColorEventArgs*
}
protected virtual void onColorEvent(object sender, ColorEventArgs e)
{
EventHandler<ColorEventArgs> ceh = ColorEventHandler;
{
if (ceh != null)
{
ceh(sender, e)
}
}
}
public event EventHandler<ColorEventArgs> ColorEventHandler;
}
Custom Event Args
public class ColorEventArgs : EventArgs
{
public Color xColor { get; set; }
}
Event Handler
public void handle_ColorChanges(object sender, ColorEventArgs e)
{
if (sender is Button)
{
var ButtonSender = (Button)sender;
ButtonSender.BackColor = e.xColor;
}
}
So the edited questions are:
Is use of the EventHandler(TEventArgs) Delegate useful? MS documentation indicates that syntax like
button1.Click += new EventHandler<AutoRndColorEventArgs>(handle_ColorChanges);
is correct, but that will not reach my code to randomly select a color and an error
"No overload for 'handle_ColorChanges' matches delegate >'System.EventHandler' "
so something like
button1.Click += new EventHandler<AutoRndColorEventArgs>(KK.ChangeColor(button1));
or
button1.Click += new EventHandler(KK.ChangeColor(button1));
Error says that a method is required and if I use
"No overload for 'handle_ColorChanges' matches delegate
'System.EventHandler'"
Lambda expressions help thanks for the supporting answers
button1.Click += (sender,args) => KK.ChangeColor(s);
But that doesn't allow un-assignment and that will be required later...
An anonymous delegate has the same problem
button1.Click += delegate(object sender, EventArgs e)
{ KK.ChangeColor(sender); };
The crux of the problem is that my color methods or their delegates do not match the button delegate signature (object, event). I don't care about the button args and want to use my own HOW?
Is the use of the delegate correct?
Yep, what you are doing is assigning an anonymous delegate as your event handler. This is perfectly valid, however, the catch here is you can't unassign the event handler because you have no reference to it. You could keep a reference to it and do it that way (if required)
var clickHandler = delegate { ... };
button1.Click += clickHandler;
...
button1.Click -= clickHandler
If you need access to the parameters of the event handler you will need to add those into the signature e.g.
button1.Click += delegate (object sender, EventArgs args) { ... }
The new EventHandler(SomeHandlerMethod) construct is the long way of doing things, it's synonymous to += SomeHandlerMethod. Your code currently doesn't work because you are trying to actually call the handler inside the constructor when the constructor expects a reference to the method
+= new EventHandler<ColorEventArgs>(KK.ChangeColor);
Is there a better structure for this?
Yeah, you can do it using even less code
button1.Click += (s, args) => KK.ChangeColor(button1);
This is incorrect:
button1.Click += new EventHandler<AutoRndColorEventArgs>(KK.ChangeColor(button1));
Instead of KK.ChangeColor(button1), you just need to specify the event handler method name as you did in here:
KK.ColorEventHandler += handle_ColorChanges;
The event handler method signature should match with the EventHandler delegate.If you want to just call a method in event handler, you can use lambda statement like this:
button1.Click += (s,e) => KK.ChangeColor(s);
Or:
button1.Click += delegate(object s, EventArgs e) { KK.ChangeColor(s); };
By doing this you are creating an anonymous method and attach it to your Click event.

How to connect text change event in multiple text boxes to a single method (C#)?

When I double click on my text boxes in the designed, it creates a method auto-magically for me. Since I wish the same things to occur in any of the cases, I simply call an auxiliary method from each, like in the code below.
private void TextBox_1_TextChanged(object sender, EventArgs e)
{
TextChanged();
}
private void TextBox_2_TextChanged(object sender, EventArgs e)
{
TextChanged();
}
private void TextChanged(object sender, EventArgs e) { ... }
Now I'd like to know if there's a way (other than going into my design file (which, according to the information in it, shouldn't be attempted to) to connect the actions listeners to the same method and skip the detour via the automatically generated ones.
On the designer page go to the events tab, find the event you are looking for (TextChanged) and manually enter the name of the event handler you wish them all to use.
I usually proceed like this in my projects, if controls are not going to change at runtime (i.e. if all controls in the form are added at design time):
// this is the container's ctor
public MyForm()
{
TextBox1.TextChanged += new EventHandler(UniqueHandler);
TextBox2.TextChanged += new EventHandler(UniqueHandler);
...
TextBoxN.TextChange += new EventHandler(UniqueHandler);
}
void UniqueHandler(object sender, EventArgs e)
{
TextBox source = (sender as TextBox);
// handle the event!
}
If controls will change, it's actually quite similar, it just doesn't happen in the ctor but on-site:
// anywhere in the code
TextBox addedAtRuntime = new TextBox();
addedAtRuntime.TextChanged += new EventHandler(UniqueHandler);
MyForm.Controls.Add(addedAtRuntime);
// code goes on, the new textbox will share the handler
In the properties fold-out (most often to the right of your screen) you should have a thunder icon. That's where all the events are referable.
If you don't see the properties, select the regarded component (the text box in your case), right-mouse it and pick "properties" in the context menu.
You can do it by this way:
void btn1_onchange(object sender, EventArgs e)
{
MessageBox.Show("Number One");
}
void btn1_onchange2(object sender, EventArgs e){
MessageBox.Show("Number Two");
}
public MyForm() {
Button btn1 = new Button();
btn1.Text = "Click Me";
this.Controls.Add(btn1);
btn1.TextChange += new EventHandler(btn1_onchange);
btn1.TextChange += new EventHandler(btn1_onchange2);
}
You could do it in designer view. Instead of double-clicking on an element - go to your buttons' properties, select events tab and then put a proper handler name for adequate event. Voila!
Follow these steps:
Go to the InitializeComponent().
There are three events attached to each text box.
There you shoud be able to see the following.
this.textBox1.TextChanged += new System.EventHandler(this.textBox1_TextChanged);
this.textBox2.TextChanged += new System.EventHandler(this.textBox2_TextChanged);
Replace this with
this.textBox1.TextChanged += new System.EventHandler(this.textBox1_TextChanged);
this.textBox2.TextChanged += new System.EventHandler(this.textBox1_TextChanged);
And then remove the method below
private void TextBox_2_TextChanged(object sender, EventArgs e)
{
TextChanged();
}

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 can I unsubscribe to this .NET event?

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;

Categories

Resources