I have been working on migrating from WithEvents to explicitly wiring up my event handlers in order to handle issues with events crossing the DataPortal. As mentioned in other threads, I found the need to hook the events OnDeserialized. As a result, I have found it convient to use a common HookEvents method to call both when I am creating the object and when it is returned from the DataPortal. Naturally, I don't want to hook the event to an object that has not been instantiated yet. Here is where I ran into an unexpected issue with the timing of Initialize and New when declaring private fields using the "Private _foo as New Foo" syntax.
To demonstrate, I created a couple quick classes: a person and a dog. (The sample classes follow below). The Person contains a Dog. The person can Scold (public method) a Dog which causes the dog to Bark (public property). When the dog starts barking, (PropertyHasChanged), the Person starts to hear the dog bark (Dog_PropertyChanged). After the person has heard the dog enough (Threading.Sleep), she Pets (public method) the dog causing it to stop barking.
Public
Class Person 'We can't hook the events here as _Dog is not yet initialized
'Protected Overrides Sub Initialize()
' MyBase.Initialize()
' HookEvents()
'End Sub
Public Sub New()
MyBase.New()
'_Dog is now instantiated, we can safely hook the events
HookEvents()
End Sub
Private Sub HookEvents()
If Not _Dog Is Nothing Then
AddHandler _Dog.PropertyChanged, AddressOf Dog_PropertyChanged
End If
End Sub
Private Sub Dog_PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs)
If _Dog.Barking Then
System.Threading.Thread.Sleep(1000)
_Dog.Pet()
End If
End Sub
Protected Overrides Function GetIdValue() As Object
Return 2
End Function
End Class
Public
Class DogEnd
ClassModule
Module1What I discovered is if I try to hook the events in the Initialize, the private field (_Dog) is not yet initialized and thus the event handler is never added). To test this, comment out the constructor for Person and uncomment the "Initialize" method. You will see that the final "Is Barking" value is still true (because the person never heard the property changed notification.) Instead, hook up events in the constructor (New) not the initializer (Initialize). If you are utilizing Initialize, make sure you are not accessing any fields that are not yet set. Considering this, I'm not sure the viability of the "Initialize" overload method in business tier code.
Jim Wooley
http://devauthority.com/blogs/jwooley
Andres,
Thank you for the clarification. I did test this in C# and indeed the code works properly with either the constructor or Initialize implementation. The difference makes it all the more frustrating. Hopefully this will help someone out there not be caught off-guard.
Jim
Copyright (c) Marimer LLC