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());
Related
I have multiple MacroPanels which are custom UI elements, I wanted that at a given time only a single one could be active (indicating that a macro is loaded to a hotkey), regardless of the current UI window.
internal MacroPanel()
{
InitializeComponent();
MacroPanel.Selected += MacroPanel_Selected;
this.Disposed += MacroPanel_Disposed;
}
private void MacroPanel_Disposed(object? sender, EventArgs e)
{
MacroPanel.Selected -= MacroPanel_Selected;
this.Disposed -= MacroPanel_Disposed;
}
private void MacroPanel_Selected(object? sender, EventArgs e)
{
if (this == sender)
return;
this.BackColor = Color.Yellow;
}
internal void SelectPanel()
{
this.BackColor = Color.Orange;
Selected?.Invoke(this, EventArgs.Empty);
}
I achieved the desired behaviour by having a static event inside the MacroPanel that every Macro panel instance listens to.
I know that subscribing to a static event can cause memory leaks.
The question is should MacroPanel instance unsubscribe from its own static
event after disposal?
Would it cause memory leaks or other issues if
I would not unsubscribe from the Selected event?
Is subscribing to the Disposed event a proper way to achieve this or is ther any other
probably more beneficial way?
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?
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Unsubscribe anonymous method in C#
Single-shot event subscription
Is it possible to get a reference to an event handler from within the event handler itself so you can unhook it from the event that called it?
For instance, I'd love to make the control.Loaded event point to a Lambda, but if I did, I don't know what to pass to the unhook (-=) call.
Here's an excerpt of the code:
private static void IsEnabled_Changed(object sender, DependencyPropertyChangedEventArgs e)
{
var control = (Control)sender;
if(control.IsLoaded)
WireUpScrollViewerEvents(control);
else
control.Loaded += Control_Loaded;
}
private static void Control_Loaded(object sender, RoutedEventArgs e)
{
var control = (Control)sender;
control.Loaded -= Control_Loaded; // <-- How can I do this from a lambda in IsEnabled_Changed?
WireUpScrollViewerEvents(control);
}
private static void WireUpScrollViewerEvents(Control control, bool attach)
{
var scrollViewer = Utils.FindFirstVisualChild<ScrollViewer>(control);
if(scrollViewer == null) return;
var attachEvents = GetIsEnabled(control);
if(attachEvents)
{
scrollViewer.PreviewDragEnter += ScrollViewer_PreviewDragEnter;
scrollViewer.PreviewDragOver += PreviewDragOver;
}
else
{
scrollViewer.PreviewDragEnter -= ScrollViewer_PreviewDragEnter;
scrollViewer.PreviewDragOver -= PreviewDragOver;
}
}
The only reason Control_Loaded is an actual method is because of the 'control.Loaded -= Control_Loaded' line. I’m wondering if we can anonymous-lambda away it from within the IsEnabled_Changed call directly.
Ok, found it.
Ok, found it. The reason I couldn't get it to work was I was doing this...
RoutedEventHandler Control_Loaded = (s2, e2) =>
{
control.Loaded -= Control_Loaded;
WireUpScrollViewerEvents(control);
};
...when I should have been doing this...
RoutedEventHandler Control_Loaded = null; // <-- It's now declared before it's set, which is what we need
Control_Loaded = (s2, e2) =>
{
control.Loaded -= Control_Loaded;
WireUpScrollViewerEvents(control);
};
This is because you have to actually declare the variable before you can use it, and I was trying to use it as part of the declaration. This fixes that.
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.
I want to detach the custom event but could not detach. Below I am using -= to detach the event. I assume after this, the TextChanged2 method should not be invoked as I have unregistered the event. Is my understanding wrong?
public delegate void TextChangedEventHandler1(object sender, TextBoxargs ta);
public event TextChangedEventHandler1 TextChanged1;
private void textBox1_TextChanged(object sender, EventArgs e)
{
this.TextChanged1 -= new TextChangedEventHandler1(TextChanged2);
TextChanged2(sender, e);
}
public void TextChanged2(object sender, EventArgs e)
{
textBox1.Text = textBox1.Text.ToUpper();
}
What you are doing is right. But using the following line of the code you can detach the event handler.
this.TextChanged1 -= new TextChangedEventHandler1(TextChanged2);
But on the second line you called the function directly so that it called the textchange2 function:
TextChanged2(sender, e);
I want to detach the custom event but
could not detach.
You do. You detach very well your event.
TextChanged2 method should not be
invoked as I have unregistered the
event.
It should not be invoked when this.textChanged1, but you invoke it yourself by calling TextChanged2(sender, e);
I suggest you give some more reasonable names to your methods, controls, and events. I could imagine half the confusion here stems from confusing names.
For example, in one comment to an answer, you mention that if you don't call the TextChanged2 event handler (for the TextChanged1 event...) explicitly, it will never get called. This would lead to the question when, and where, you raise the TextChanged1 event. If you have indeed subscribed the TextChanged2 handler to the TextChanged1 event with the += operator, then the handler will be invoked as soon as the event is raised.
Use
this.TextChanged1 -= TextChanged2;