attaching to an eventhandler [duplicate] - c#

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
C#: Difference between ‘ += anEvent’ and ‘ += new EventHandler(anEvent)’
Hi all,
I have two eventhandlers.
In my constructor I attach a function to the eventhandler but do it in different ways for the two eventhandlers. One with new Eventhandler, the other by just pointing to the function. They seem to do the same?
What is the prefered way and why?
UPDATE: already answered here
public partial class MyForm : Form
{
public event EventHandler Button1Clicked;
public event EventHandler Button2Clicked;
public MyForm()
{
InitializeComponent();
simpleButton1.Click += new EventHandler(simpleButton1_Click);
simpleButton2.Click += Button2Click;
}
void simpleButton1_Click(object sender, EventArgs e)
{
if (Button1Clicked != null)
{
Button1Clicked.Invoke(sender, e);
}
}
void Button2Click(object sender, EventArgs e)
{
if (Button2Clicked != null)
{
Button2Clicked.Invoke(sender, e);
}
}
}

C# 2 introduced method group conversions which is what your second form is using. It does exactly the same thing internally - in both cases, it produces a new instance of EventHandler.
Personally I prefer the second form: it doesn't have as much cruft. It just says what you're interested in.
(I hadn't spotted the exact duplicate. Leaving this answer here despite closing the question, as it's doing no harm.)

yes they do the same.
Resharper recomemnds latter.

Both of the way of attaching event handler are same. In the last case framework (fro 2.0 onward) is able to infer type itself.

Related

Do you have to ubsubscribe from Disposed? [duplicate]

This question already has answers here:
Do I need to unsubscribe events in my Form?
(4 answers)
Unsubscribing from an event
(3 answers)
C# .NET proper event subscribing and un-subscribing
(3 answers)
What best practices for cleaning up event handler references?
(6 answers)
Closed 3 years ago.
I've heard that you are supposed to unsubscribe from events on controls that get disposed.
TextBox textBox;
void Initialize()
{
textBox = new TextBox();
textBox.Click += ClickHandler;
this.Disposed += DisposeControl;
}
void ClickHandler(object sender, EventArgs e)
{
this.foo = bar;
}
void DisposeControl(object sender, EventArgs e)
{
textBox.Click -= ClickHandler;
this.Disposed -= DisposeControl; // DOES THIS LINE MAKE SENSE?
}
There's no reference to the control after it has been disposed so I would assume there is no need to unregister any event handlers. Yet, as I mentioned people are saying that you're supposed to. Does that include unregistering the dispose event itself?
To answer you question "DOES THIS LINE MAKE SENSE?", in your example it does not. That is because the event source and target are both the same. I am going to rewrite your code a bit.
class SOTest1 : Control
{
private bool bar = true;
private bool foo { get; set; }
TextBox textBox;
void Initialize()
{
textBox = new TextBox();
textBox.Click += ClickHandler;
this.Disposed += DisposeControl;
}
void ClickHandler(object sender, EventArgs e)
{
this.foo = bar;
}
void DisposeControl(object sender, EventArgs e)
{
textBox.Click -= ClickHandler;
this.Disposed -= DisposeControl; // DOES THIS LINE MAKE SENSE?
}
}
In this case, since Control implements IDisposable which calls the Disposed event at the end of the disposal, both the object with the event and the event handler are the same object. So, the C# garbage collector is going to see that the object and all references have been disposed and will clean it all up.
Also, since textBox and its event handlers are contained within that object, the textBox.Click -= ClickHandler is also redundant, as it will all be cleaned up by the GC when the SOTest1 object is disposed.
It's not a bad practice to clean up event subscribers, but, it does add code that is unnecessary much of the time. C# does a great job of cleaning up resources when your code has finished with them.
There are some cases where memory leaks can happen, like if the lifecycle of the object with the handler is shorter than the lifecycle of the object with the event. The main answer in this article has a good example of that case: What best practices for cleaning up event handler references?
I prefer use IDisposable to handle this case
List<IDisposable> eventsToDispose = new List<IDisposable>();
eventsToDispose.Add(Disposable.Create(() =>
{
textBox.Click += ClickHandler;
}));
Then you can dispose handler
eventsToDispose.ForEach(o => o.Dispose());

C# Simplifying a click event method to include other controls [duplicate]

This question already has answers here:
Identify who invokes Event Handler
(2 answers)
How to create an event handler for multiple buttons?
(3 answers)
How to write a common ClickEvent for many labels?
(4 answers)
clear mutiple textboxes by reusing an event handler
(1 answer)
Is it safe to use the same event handler for different Windows Forms Controls?
(7 answers)
Closed 5 years ago.
I was looking to simplify the following action: Click on a panel, and the panel changes its color to green, and if it is green, change it back to gray. I was wondering how you would write the controls into the method as an argument so that it would work for any control without having to duplicate the event method.
Normally: Panel Click event
panel_Click ()
//some if statement
panel1.BackColor = green
panel1.BackColor = gray
then repeat per control. Instead of this, I would create a central method that all of the controls are subscribed to, that read the name of the panel like:
genericpanel_Click(){
ChangeColor(thisPanelname);
}
and then that would make use of the argument/parameter:
public void ChangeColor(panel? Mypanel) {
//some if...
Mypanel.BackColor = Green
Mypanel.BackColor = Gray
}
What's the accurate equivalent of this pseudo code into a working one?
Edit: Okay, yes, I can see now that it's a duplicate, no need to downvote further. I just didn't know what to search for specifically. Anyways, I've found the answer at this point.
All events of a control provide its source as the first argument. You just have to cast it to the right type:
void panel_Click(object sender, EventArgs e) {
Panel myPanel = (Panel)sender;
ChangeColor(myPanel);
}
All definitions for event handler delegates provide the sender, for example:
public delegate void EventHandler(object sender, EventArgs e);
public delegate void EventHandler<T>(object sender, T e);
In case you define your own events, just use those delegate types and pass the source of the event as the first argument.
You can subscribe all panels to this method:
private void panel_Click(object sender, EventArgs e)
{
Panel clickedPanel = sender as Panel;
if ( clickedPanel != null )
{
if ( clickedPanel.BackColor == Color.Blue )
{
clickedPanel.BackColor = Color.Red;
}
else
{
clickedPanel.BackColor = Color.Blue;
}
}
}
If you only subscribe panels to this even the first check wouldn't be needed, but to be safe its there.
This method takes the sender (the panel that activated the event) and check's its background color. If color A set to Color B -> else Color A

Action when Form is closed c#

I'm in College and this is my first (major) project.
I'm trying to perform an action when a form is closed. I don't seem to be getting the terminology right when searching online, or the answer given doesn't match what I want to do.
At the moment i'm declaring a Class and displaying the from -
private void createuser_Click(object sender, EventArgs e)
{
User_Modification mod = new User_Modification("Create", "Create");
mod.ShowDialog();
}
What I want to do is this -
WHEN mod IS CLOSED {
// Do stuff
}
You're using ShowDialog, so the code following it is not executed until after the dialog box is closed. mod.ShowDialog(); doStuff(); will work pretty well.
You need to create a handler to capture the FormClosed event:
In your constructor do:
this.FormClosed += Form_Closed;
Then in the body of your form, add this method.
private void Form_Closed(object sender, FormClosedEventArgs e)
{
// Do stuff
}
You should attach handler to FormClosed event:
private void createuser_Click(object sender, EventArgs e)
{
User_Modification mod = new User_Modification("Create", "Create");
mod.FormClosed += new FormClosedEventHandler(FormClosed);
mod.ShowDialog();
}
void FormClosed(object sender, FormClosedEventArgs e)
{
MessageBox.Show("Closed");
}
if you're using WinForms you can override OnFormClosing event:
protected override void OnFormClosing(FormClosingEventArgs e)
{
base.OnFormClosing(e);
// your code...
}
You'll want to take a look at two events:
Form.FormClosing : https://msdn.microsoft.com/en-us/library/system.windows.forms.form.formclosing(v=vs.110).aspx
Form.FormClosed : https://msdn.microsoft.com/en-us/library/system.windows.forms.form.formclosed%28v=vs.110%29.aspx
First one will allow you to perform actions prior to the form being closed completely, such as canceling the closing procedure. The second one is what you would use if you want to perform actions after the form is closed (perhaps to clean up resources, as an example).
So, as an example, let's say that you want to perform an action when the form is in fact closed:
// Somewhere in your code where you create the form object.
form.FormClosed += Form_FormClosed;
// Somewhere else in your code.
private void Form_FormClosed(Object sender, FormClosedEventArgs e)
{
MessageBox.Show("Form closed");
}

How to check if the object already has the a specify event set

I have a class named MifareReader. I instantiate it as Global So i Have on my form_load:
MifareReader mf = new MifareReader()
private void Main_Load(object sender, EventArgs e)
{
mf.MyEvent += new EventName(My_Method);
Connect();
}
private void My_Method()
{
//Code Here
}
private void Connect()
{
//Some Code Here
mf.MyEvent += new EventName(My_Method); //The same code of the Main_Load
}
Now let me explain. On my Main_Load I've set the event MyEvent and set it's method to My_Method Right ? Also, I called the other method Connect(), this methods repeat what i've done on the Main_Load
mf.MyEvent += new EventName(My_Method);
Right ?
So, I don't know why, but if I do not repeat this code, the application DOES NOT fire the MyEvent without Closing/Reopening the application.
Ok, its working perfect the way it is, but when I close/reopen my application, it fires MyEvent twice. So, Is there a way to work around this ?
Maybe check if the mf.MyEvent has already a method set to it?

Passing custom arguments to event handler [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Passing arguments to event handler
I'm trying to handle an event raised from a MenuItem.Click. The catch is, I need some way to pass some custom arguments with it (specifically, two integers representing row and column).
private void Window_Loaded(object sender, RoutedEventArgs e)
{
...
MenuItem froNewChild = new MenuItem();
froNewChild.Header = "Insert new box";
froNewChild.Click += new RoutedEventHandler(froNewChild_Click);
// froNewChild.Click += new RoutedEventHandler(froNewChild_Click, column, row);
FlowRectangleOptions.Items.Add(froNewChild);
...
}
private void froNewChild_Click(object sender, RoutedEventArgs e) //+column & row
{
FlowDocument.allColumns[column-1].AddFlowRectangle(column, row);
FlowDocument.ReRenderAll(canvas1);
}
This answer Passing arguments to an event handler would seem to do what I want, but doesn't work as-is because sender is already defined in this scope. Sadly I don't know enough yet to work around that problem - advice greatly appreciated!
Assumming "column" and "row" are created in your loaded method, you could just use a Lambda event handler so you can pass the variables in.
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
//Assumming "column" and "row" are in this block somewhere.
...
MenuItem froNewChild = new MenuItem();
froNewChild.Header = "Insert new box";
froNewChild.Click += (s, eArgs) =>
{
FlowDocument.allColumns[column - 1].AddFlowRectangle(column, row);
FlowDocument.ReRenderAll(canvas1);
};
FlowRectangleOptions.Items.Add(froNewChild);
...
}
The argument passed to the evant handler depends on how the raising class is designed, and they are passed as a class derived from EventArgs as a second argument. Augmenting this is not possible unless you are the designer of the class raising the event. In this particular case we are talking about a framework class and so it is not possible at all.
As a workaround you can define some state member variable in your class and use them to pass informations to the handler.
sa_ddam213 already answered you but just to clarify: the parameter names in lambda expressions carry no semantic meaning and can be whatever you want. The names sender and eventArgs were only used for clarity in the question you linked. What matters in this case is that there are two params and the compiler infers the rest by himself.
The values of column and row will be captured at the point you define the lambda and will be available when the event handler executes even if MainWindow_Loaded has long ago returned and the original variables destroyed.
For more about lambda expressions in C#: http://msdn.microsoft.com/en-us/library/bb397687.aspx

Categories