Handles vs. AddHandler - vb.net

Is there an advantage to dynamically attaching/detaching event handlers?
Would manually detaching handlers help ensure that there isn't a reference remaining to a disposed object?

I'm pretty sure that the Handles clause is just syntactic sugar and inserts an AddHandler statement into your constructor. I tested using this code and disabled the application framework so the constructor wouldn't have extra stuff:
Public Class Form1
Public Sub New()
' This call is required by the Windows Form Designer. '
InitializeComponent()
' Add any initialization after the InitializeComponent() call. '
AddHandler Me.Load, AddressOf Form1_Load
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim breakpoint As Integer = 4
End Sub
End Class
The IL ended up like this:
IL_0000: nop
IL_0001: ldarg.0
IL_0002: call instance void [System.Windows.Forms]System.Windows.Forms.Form::.ctor()
IL_0007: nop
IL_0008: ldarg.0
IL_0009: ldarg.0
IL_000a: dup
IL_000b: ldvirtftn instance void WindowsApplication1.Form1::Form1_Load(object,
class [mscorlib]System.EventArgs)
IL_0011: newobj instance void [mscorlib]System.EventHandler::.ctor(object,
native int)
IL_0016: call instance void [System.Windows.Forms]System.Windows.Forms.Form::add_Load(class [mscorlib]System.EventHandler)
'... lots of lines here '
IL_0047: ldarg.0
IL_0048: callvirt instance void WindowsApplication1.Form1::InitializeComponent()
IL_004d: nop
IL_004e: ldarg.0
IL_004f: ldarg.0
IL_0050: dup
IL_0051: ldvirtftn instance void WindowsApplication1.Form1::Form1_Load(object,
class [mscorlib]System.EventArgs)
IL_0057: newobj instance void [mscorlib]System.EventHandler::.ctor(object,
native int)
IL_005c: callvirt instance void [System.Windows.Forms]System.Windows.Forms.Form::add_Load(class [mscorlib]System.EventHandler)
IL_0061: nop
IL_0062: nop
IL_0063: ret
} // end of method Form1::.ctor
Notice two identical blocks of code around IL_000b and IL_0051. I think it's just syntactic sugar.

It's not a question of using AddHandler versus Handles.
If you are concerned about the reference to your event handler interfering with garbage collection, you should use RemoveHandler, regardless of how the handler was attached. In the form or control's Dispose method, remove any handlers.
I have had situations in Windows Forms apps (.NET 1.1 days) where an event handler would be called on controls that had no other references to them (and which for all intents and purposes were dead and I would have thought been GC'ed) -- extremely hard to debug.
I would use RemoveHandler to get rid of handlers on controls that you are not going to reuse.

Declaring a field as WithEvents will cause the compiler to automatically generate a property with that name. The getter returns the value of a backing field. The setter is a little more complicated. It first checks whether the backing field already has the correct value. If so, it exits. Otherwise, if the backing field is non-null, it issues "RemoveHandler" requests for all its events to the object identified by the backing field. Next, regardless of whether the backing field was non-null, it sets it equal to the requested value. Finally, if the new value is non-null, whether the old one was or not, the property issues "AddHandler" requests for all its events to the object identified by the new value.
Provided that one sets all of an object's WithEvents members to Nothing before abandoning it, and avoids manipulating WithEvents members in multiple threads, the auto-generated event code will not leak.

I find that dynamically attaching/detaching event handlers is only of use where you have a long-lived object exposes events that are consumed by many short-lived objects. For most other cases the two objects are disposed around the same time and the CLR does a sufficient job of cleaning up on its own

I manually attach handlers when I manually create controls (for example, dynamically creating a TextBox for each database record). I manually detach handlers when they are handling things I'm not quite ready to handle yet (possibly because I'm using the wrong events? :) )

Manually detaching an event can be important to prevent memory leaks: the object that connects to an event fired by another object, will not be garbage collected until the object that fires the event is garbage collected. In other words, an "event-raiser" has a strong reference to all the "event-listeners" connected to it.

Most of the time the framework takes care of that for you.

Related

ExpandoObject PropertyChanged event not triggering in propertygrid

Basically I am loading a JSON object that contains combinations of values available or not at run time, so I need to know when a specific property is modified to then toggle all the other browsable etc.. and though that the PropertyChange event was the perfect way to handle it.
So I can add an event handler to get triggered on my expandoobject like this:
Dim test As Object = new ExpandoObject
AddHandler CType(test, INotifyPropertyChanged).PropertyChanged, AddressOf expando_PropertyChanged
and the handler is as basic as it gets
Public Shared Sub expando_PropertyChanged(ByVal sender As Object, ByVal e As PropertyChangedEventArgs)
Debug.Print("Property {0} set or changed", e.PropertyName)
End Sub
so far this works, if I add or modify a property right after that, I get notified.
however if I return this and set it as the selectedobject of my propertygrid, I cannot get the event to trigger.
I'm using a custom PropertyDescriptor and ICustomTypeDescriptor to set a few other attributes for the propertygrid, so I assumed it might be as easy as setting the attribute
<RefreshProperties(RefreshProperties.All)>
but I cannot find a way to override the Refresh in the PropertyDescriptor unlike Browsable or readonly, which kinda makes sense as the property grid would need to know ahead of time that it needs to be refreshable.
So I could not make the INotifyPropertyChanged work with the expando, it would work with a dynamicObject where I would implement it myself but that was requiring too much of a rewrite for me.
I ended up add a lambda on my expando that I call on the PropertyDescriptor SetValue
CType(_expando, Object).toggleSwitches.Invoke(_expando, _name, value)
note the use of Invoke here in vb.net that was also a PITA but I found this guy who had the same issue as I did: https://github.com/dotnet/vblang/issues/226
It is not necessary to use invoke in C# and as 99% of the examples are in C# it took me more time than I wanted to implement it.
Hopefully this will help someone too.
here is the lambda if interested as well:
_expando.toggleSwitches = Sub(obj As Object, caller As String, value As Object)
Debug.Print(caller & " " & value.ToString())
End Sub

Multi-Thread (Append Text To TextBox)

Done my fair share of looking this up but it just doesn't make sense..
I know we have to use delegates to update a textbox thats on the Main UI.
Here is the code in the a nutshell:
Initiate the thread that will capture chats:
ChatQuery = New Thread(AddressOf FetchChats)
ChatQuery.Start()
FetchChats Code Simplified:
SetTextBoxWithInvoke(Form5.TextBox2, MESSAGE)
SetTextBoxWithInvokeCode:
Private Sub SetTextBoxWithInvoke(ByVal TB As TextBox, ByVal msg As String)
If TB.InvokeRequired Then
TB.Invoke(New AddToMessageBoxDelegate(AddressOf SetTextBoxWithInvoke), New Object() {TB, msg})
Else
TB.Text &= msg
End If
End Sub
The Problem?? Invoke is never required, and the new message is never appended to the textbox I need to be appended to.
Delegate:
Public Delegate Sub AddToMessageBoxDelegate(ByVal TB As TextBox, ByVal msg As String)
The problem is that you're using the default instance of the form here:
SetTextBoxWithInvoke(Form5.TextBox2, MESSAGE)
Default instances are thread-specific so, if you execute that code on a background thread, rather than using the existing Form5 instance that was created and displayed on the UI thread, it will create a new instance on the current thread. There's no need to invoke a delegate to access that instance so InvokeRequired is always False.
You need to use the actual instance of Form5 that already exists. How exactly you do that depends on the circumstances. If the code that makes the call is already in that form then just use Me, which is implicit if you don't explicitly use another reference anyway. Otherwise, it's up to you to get the required reference into the required object to be used.
If the code is not in a form already then maybe you should not be doing it that way at all. Instead, you can use the SynchronizationContext class. You get the current instance when your object is created on the UI thread and you can then call its Send or Post method to marshal back to the UI thread without an explicit Control reference. That might not work in your case though, because you'd still need a reference to the correct TextBox.

Totally form Disposing and free up memory

I already read a ton of topics "class disposing" about and I did understand how to do it and it works fine! Meanwhile "form disposind" is not same and resources still leaking!
What I am doing:
Initializing form by "using" method:
Using f as New Form
f.ShowDialog()
'my code
End using
In this case by "end using" form terminated with "Dispose" method.
For example:
I have a form which have a class (it contain parameters and other classes).
On initialization form event, form (itself) take 12Mb of memory (I measure it in process explorer) and plus my class take 10Mb (which Disposable and also disposing before Dispose form on Dispose event). After my form disposed (I measure it again) I see my class disposed and resources (of class) are free totaly, the form is not freeing resources. In other words I kill 10Mb (of class) BUT DON'T kill 12Mb (of form).
My Dispose code:
Private Sub Form_Disposed(sender As Object, e As EventArgs) Handles
Me.Disposed
If Not fDisposed Then
MyPersonalClass.Dispose()'class
MyPersonalClass = Nothing
fDisposed = True
GC.SuppressFinalize(Me)
GC.Collect()
Finalize()
End If
End Sub
It's very bad. If most of time I working with these forms and if they are don't free resources after dispose, each opened form will be leave approx 10-12Mb in memory after closed. And if I open my form 100 times it will freezes more then 1Gb of memory.
What I doing wrong?
I'm not really familiar with VB, but I think it will do things similar as to how they are done using winforms for C#
The easiest way to make sure that all Disposable objects of A Form are disposed when the form is disposed, to keep a collection of Disposable objects. You could use the existing class Sytem.ComponentModel.Component class for this. The disadvantage is that it only accepts objects that implement interface IComponent. If you have only a few classes that must be disposed that don't have this interface yet, this is the easiest method. Otherwise design your own DisposableCollection
class DisposableCollection : List<object>, IDisposable
{
public bool IsDisposed {get, private set} = false;
private IEnumerable<IDisposable> DisposableItems => this.OfType<IDisposable>();
public void Dispose()
{
if (!this.IsDisposed)
{
// Dispose all disposable items
foreach (IDisposable disposableItem in this.DisposableItems)
{
disposableItem.Dispose();
}
this.disposed = true;
}
}
}
Usage:
class MyForm : Form
{
private readonly DisposableCollection disposables = new DisposableCollection();
public MyForm()
{
// create and add all your items to disposables
}
protected override void OnDisposing(bool disposing)
{
this.disposables.Dispose();
}
}
If desired you can add event handlers to notify others that the object is being disposed

When are a module's variables in VB.NET instantiated?

I was wondering where in the lifetime of the program a variable that is in a module would be initialized as in this example:
Module Helper
Friend m_Settings As New UserSettings()
Sub Foo()
'...
End Sub
Sub Bar()
'...
End Sub
End Module
Public Class UserSettings
Public Property UserName As String
Public Property PrefServer As Integer
Public Sub New()
'...
End Sub
Public Sub LoadSettings()
'...
End Sub
End Class
When would m_Settings be initialized? I can set a break point at the constructor for UserSettings and look at the call stack, but I see "External Code" in there but that doesn't tell me a lot.
The CLR has no direct support for VB.NET modules, it requires all methods and variables to be part of a type. So the VB.NET compiler actually generates a class under the hood. All of the functions you wrote in the module become static methods of that class. All of the variables you declared in the module become static fields of the class.
Any variables that are initialized in your module causes a static constructor to be generated. And the initialization code is moved into this constructor.
Now CLR rules apply: a soon as the jitter touches any of the members of this class, the CLR runs the static constructor. Which then initializes all of the module variables. Which is also why you see [external code] on the call stack, the call originated inside the CLR.
It is rare to have problems with this, the static constructor guarantee in the CLR is a very strong one. About the only tricky mishap is a variable initializer that causes an exception to be thrown. That's when the guts start showing. The stack trace is pretty mystifying since it shows code that doesn't exist in your source code. The actual exception thrown is a TypeInitializationException, very mystifying since you didn't write any type, you need to look at its InnerException to find the real reason.

Threading: Call a delegate from a separate thread (VS2010)

So, I'm having troubles implementing a separate thread. This is because I have a simple class, and in it I start a new thread. So, as it is not any form, I haven't found any way to make it call the function in the UI Thread.
So, I cannot use the Invoke method. Is there any way to call a function from another thread?
I am going to assume that you have events exposed from your class and that you want the event handlers to execute on a UI thread. I suppose you could have a callback that the caller specifies as well. Either way the pattern I will describe below will work in both cases
One way to make this happen is to have your class accept an ISynchronizeInvoke instance. Form and Control instances implement this interface so a reference to one of them could be used. You could make it a convention that if the an instance is not specified then event handlers executed by raising events on your class would execute in the worker thread instead of the thread hosting the ISynchronizeInvoke instance (usually a form or control).
Public Class YourClass
Private m_SynchronizingObject As ISynchronizeInvoke = Nothing
Public Sub New(ByVal synchronizingObject As ISynchronizeInvoke)
m_SynchronizingObject = synchronizingObject
End Sub
Public Property SynchronizingObject As ISynchronizeInvoke
Get
Return m_SynchronizingObject
End Get
Set(ByVal value As ISynchronizeInvoke)
m_SynchronizingObject = value
End Set
End Property
Private Sub SomeMethodExecutingOnWorkerThread()
RaiseSomeEvent()
End
Private Sub RaiseSomeEvent()
If Not SychronizingObject Is Nothing AndAlso SynchronizingObject.InvokeRequired Then
SynchronizingObject.Invoke(New MethodInvoker(AddressOf RaiseSomeEvent)
End If
RaiseEvent SomeEvent
End Sub
End Class
The first thing to notice is that you do not have to specify a synchronizing object. That means you do not have to have a Form or Control reference. If one is not specified then SomeEvent will be raised on the worker thread. This is the same pattern that is used in the System.Timers.Timer class.
Try to expose some events in your class, fire them when you need to notify your UI and finally make your UI Component register to these events,
when the event is fired, the listener methods will be executed. there you can use Control.Invoke or Control.BeginInvoke to execute your code on the UI thread.