Link to home
Create AccountLog in
Avatar of rocky050371
rocky050371

asked on

Base Class Event Question

I am working through a base case example in MVVM and classes which inherit from it raise the following

   MyBase.OnPropertyChanged("Selection")


    Protected Sub OnPropertyChanged(ByVal strPropertyName As String)

        If Me.PropertyChangedEvent IsNot Nothing Then

Why does it check whether the event is nothing, surely it raises the event irrespective


            RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs(strPropertyName))
        End If
 
    End Sub
ASKER CERTIFIED SOLUTION
Avatar of Wim_Bl
Wim_Bl
Flag of Belgium image

Link to home
membership
Create an account to see this answer
Signing up is free. No credit card required.
Create Account
Avatar of Mike Tomlinson
Good answer by Wim_Bl.  In C# it will throw an exception if you attempt to raise an event that has no subscribers.  In VB.Net it will happily "raise" the event without any complaints even if no one is subscribed.
Avatar of rocky050371
rocky050371

ASKER

Surely the fact it is declared

 Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged

    Protected Sub OnPropertyChanged(ByVal strPropertyName As String)

        If Me.PropertyChangedEvent IsNot Nothing Then
            RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs(strPropertyName))
        End If

I still don't understand how it would be nothing


    End Sub
It doesn't make sense in VB.Net.  It would only make sense if it were C# code (as Wim_Bl has already stated).

Plus, look closely at the code you've posted:

    If Me.PropertyChangedEvent IsNot Nothing Then

Where is "PropertyChangedEvent"?  Your event is called "PropertyChanged".

For the C# explanation, see:
http://msdn.microsoft.com/en-us/library/aa645739(VS.71).aspx

    "Invoking an event - Once a class has declared an event, it can treat that event just like a field of the indicated delegate type. The field will either be null, if no client has hooked up a delegate to the event, or else it refers to a delegate that should be called when the event is invoked. Thus, invoking an event is generally done by first checking for null and then calling the event."

    if (Changed != null)
        Changed(this, e);
Sorry I did not see the PropertyChangedEvent difference, so in VB.net it is not needed as it will always call RaiseEvent?


In the C# explanation is states if no client is hooked up to a delegate, I take it they operate in a different way and they are not simply raised from the object?

Sorry for the questions just trying to get my head around this
SOLUTION
Link to home
membership
Create an account to see this answer
Signing up is free. No credit card required.
Create Account
If you want to understand what is happening under the hood, and what VB is hiding from you, then read:
http://msdn.microsoft.com/en-us/magazine/cc188776.aspx
Thanks so much, great explanation
Just one last word on this: it actually does do something in VB.Net! I tested this myself, convinced that is doesn't make sense, but I was mistaken. It is true that you can always raise the event, even without any subscribers. But the check "Me.PropertyChangedEvent" does produce True if there is at least one subscriber, and otherwise False. So just as the delegate mechanism is hidden for the developer, this property gets added and updated as well. So you can use it if you want, but there's no actual need. Btw: I tested this in VS2010, .Net 4.0, so I can't say for sure about other versions.

Glad to have helped you out!
Can you post your test code Wim_Bl?
Sure, here it goes. If you remove the AddHandler, the event will no longer be raised because of the check.

Imports System.ComponentModel

Public Class Form1
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim t As New Test
        AddHandler t.PropertyChanged, AddressOf Me.PropertyChangedHandler
        t.Name = "Testing"
    End Sub

    Private Sub PropertyChangedHandler(ByVal sender As Object, ByVal e As PropertyChangedEventArgs)
        MessageBox.Show("Property " & e.PropertyName & " has changed")
    End Sub
End Class

Public Class Test
    Implements INotifyPropertyChanged

    Private m_name As String

    Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged

    Public Property Name As String
        Get
            Return m_name
        End Get
        Set(ByVal value As String)
            m_name = value
            ' this will only pass if there is a handler attached
            If Me.propertychangedevent IsNot Nothing Then
                RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Name"))
            End If
        End Set
    End Property
End Class

Open in new window



Greetings
Thanks for posting back.

I found the documentation on this:
http://msdn.microsoft.com/en-us/library/aa711966%28VS.71%29.aspx

In addition to the member name added to the type's declaration space, an event declaration implicitly declares several other members. Given an event named X, the following members are added to the declaration space:

    "If the form of the declaration is a method declaration, a nested delegate class named XEventHandler is introduced. The nested delegate class matches the method declaration and has the same accessibility as the event. The attributes in the parameter list apply to the parameters of the delegate class.
- A Private instance variable typed as the delegate, named XEvent.
- A method named add_X, which takes the delegate type and has the same access type as the event.
- A method named remove_X, which takes the delegate type and has the same access type as the event."

So if your event is called Foo():

    Public Event Foo()

You can use "FooEvent" (which was added for you behind the scenes):

    If Not IsNothing(FooEvent) Then
        RaiseEvent Foo()
    End If

I hadn't realized this hidden delegate was accessible in this manner.

Thanks!  Learned something new today.

*I'll stick to "RaiseEvent" myself.  =)