How does NotifyPropertyChanged work in the BindableBase class?

Sep 1, 2014 at 9:06 PM
Hi all,

In order to fully understand what is happening and when, I have been stepping through the code when a property changes. I wonder how the View can EVER get the right data to show when it is binding to that property.

Let me explain.

Suppose I have a property declared as:
    Private Property PrivateMyFavorite As MyObjectType
    Public Property MyFavorite As MyObjectType
        Get
            Return PrivateMyFavorite 
        End Get
        Set(value As MyObjectType)
            SetProperty(PrivateMyFavorite , value)
        End Set
    End Property
Suppose I have a View binding to MyFavorite, so it should react to changes / updates when they are fired via NotifyPropertyChanged.

Whenever the property changes in code of the ViewModel, the Set and so the SetProperty are invoked. The BindableBase takes over, and if the original value of the property is different from the new value, it raises the PropertyChanged event for that property.

Immediately in reaction to that PropertyChanged event, the View does a request to the property and invokes the Get method of the property.

But and that is my question: the 'PrivateMyFavorite' has not yet been updated at that point, so "nothing" will be returned to the View.

So how is it possible that the View could receive the correct propertyvalue on the Get?

After the Get that originated from the View, the BindableBase gives the command back to the ViewModel, and there the Setter does his work. So just after the View did a Get, the PrivateMyFavorite receives the new value.

Where am I wrong in this presumption of the inner working of BindableBase? And If I am wrong, how come that in my excercises the View does not get the correct property when it binds to it?

Who is capable of illuminating my dark hours?
Sep 2, 2014 at 8:25 AM
BindableBase works different than you said:
protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
        {
            if (object.Equals(storage, value)) return false;

            storage = value;
            this.OnPropertyChanged(propertyName);

            return true;
        }
It first checks on equality and if false it sets the new value on the pointer (ref) of the variable (storage). The ref keyword is essential here because you can also pass value types as int or boolean and thus they are living on the heap they would just be copied and after the function exits you would have your old variable.

I hope I was able to bring some light to you ;-)

Link for BindableBase: http://pnpmvvm.codeplex.com/SourceControl/latest#Prism.Mvvm/BindableBase.cs
Sep 3, 2014 at 1:13 PM
Thanks ViktorHofer,

It sure brings some light, but stepping through the code I still notice this sequence:
  1. SetProperty is called
  2. storage = value
  3. OnPropertyChanged is called
  4. The PropertyChanged event is fired, and thus NotifyPropertyChanged
  5. Based on the Binding to the property the View immediately tries to Get PrivateMyFavorite, who's value has not been updated yet.
  6. The property Setter finishes, so PrivateMyFavorite is updated.
As far as I can see it happening, I see that the call to the Getter is too early, or the call to the Setter is too late.

point number 5 in my list is the assumption I make about the reaction of the View based on the ProperyChanged event.

So my question remains: how can the View ever have the right value out of the Getter of the property?
Sep 3, 2014 at 9:03 PM
But you are showing that storage = value is called before OnPropertyChanged. So 2 is before 3 which means that the new value is set before the OnPropertyChanged event is fired. I don't know why you are having troubles... I haven't had any of your issues with Prism C#. I call SetProperty(ref myVariable, newValue) and thats it...
Sep 3, 2014 at 9:31 PM
Hi ViktorHofer,

Glad for you that you don't have any trouble. Unfortunately it fails on my side, even though I use the same C# libray (I guess, downloaded the last version for WinRT 8.1).

Because this appears NOT to work, I decided to override/shadow the functionality of the BindableBase class, and implemented in the ViewModel the simple Inherited INotifyPropertyChanged. A few lines of code more. But of course: in every viewmodel I have to repeat myself... :-(
Doing that, I get everything running immediately.

So to summarize:
    Private Property PrivateMyFavorite As MyObjectType
    Public Property MyFavorite As MyObjectType
        Get
            Return PrivateMyFavorite 
        End Get
        Set(value As MyObjectType)
            SetProperty(PrivateMyFavorite , value)
        End Set
    End Property
does NOT work in my VB implementation.


This is what works immediately and flawless:
Implements INotifyPropertyChanged

Public Shadows Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged

Private Sub NotifyPropertyChanged(<CallerMemberName()> Optional ByVal propertyName As String = Nothing)
    RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub


Private Property _PrivateMyFavorite As MyObjectType
Public Property ActuelePersoon As MyObjectType
    Get
        Return _PrivateMyFavorite 
    End Get
    Set(value As MyObjectType)
        _PrivateMyFavorite = value
        NotifyPropertyChanged()
    End Set
End Property
Bottomline is that I am a bit disappointed in the functionality of the Prism library at this point. I completely will agree with everyone else that:
  1. I should not get any trouble with it, or (as some others have replied to me as well: it should work with this library.
  2. I don't see how I could tweak the library to get it working. The BindableBase is pretty straightforward and does not do a lot of complicated heavy lifting.
All the best and thank you for all yours efforts to assist me!
Sep 4, 2014 at 8:27 AM
Ok lets settle this once and for all. This is my test console application written in VB VS2013.3 (my first ever VB.Net application mind you). I added a reference to this package
<package id="Prism.Mvvm" version="1.1.1" targetFramework="net451" />
I have the following Test classes :
Public Class Test
    Inherits Microsoft.Practices.Prism.Mvvm.BindableBase

    Dim _myFavoriteString As String
    Dim _myfavoriteObject As TestItem

    Public Property MyFavoriteString As String
        Get
            Return _myFavoriteString
        End Get
        Set(value As String)
            SetProperty(_myFavoriteString, value)
        End Set
    End Property

    Public Property MyFavoriteObject As TestItem
        Get
            Return _myfavoriteObject
        End Get
        Set(value As TestItem)
            SetProperty(_myfavoriteObject, value)
        End Set
    End Property
End Class

Public Class TestItem
    Public Name As String
End Class
And I used this Console application to test the SetProperty functionality raising the Property Changed event:
Module Module1
    Sub Main()
        Dim x = New Test

        AddHandler x.PropertyChanged, AddressOf PropertyChanged

        Console.WriteLine("Before String change '{0}'", IIf(IsNothing(x.MyFavoriteString), "Nothing", x.MyFavoriteString))
        x.MyFavoriteString = "Test"
        Console.WriteLine("After String changed to {0}", IIf(IsNothing(x.MyFavoriteString), "Nothing", x.MyFavoriteString))

        Dim item = New TestItem()
        item.Name = "Peter"

        Console.WriteLine("Before Object change '{0}'", IIf(IsNothing(x.MyFavoriteObject), "Nothing", "Something"))
        x.MyFavoriteObject = item
        Console.WriteLine("After Object changed to {0}", IIf(IsNothing(x.MyFavoriteObject), "Nothing", x.MyFavoriteObject.Name))

        RemoveHandler x.PropertyChanged, AddressOf PropertyChanged
        Console.ReadLine()
    End Sub

    Public Sub PropertyChanged(sender As Object, e As PropertyChangedEventArgs)
        Console.WriteLine("PropertyChanged: {0}", e.PropertyName)
    End Sub
End Module
This generated the following output in the console window:
Before String change 'Nothing'
PropertyChanged: MyFavoriteString
After String changed to Test
Before Object change 'Nothing'
PropertyChanged: MyFavoriteObject
After Object changed to Peter
What this tells me is that Prism.MVVM works fine as expected. Also that there is nothing special to do within a class to get the PropertyChanged event to be raised if using the SetProperty method supplied by BindableBase.

Extending the Module1 test as follows:
    Console.WriteLine("Before String change '{0}'", IIf(IsNothing(x.MyFavoriteString), "Nothing", x.MyFavoriteString))
    x.MyFavoriteString = "Test"
    Console.WriteLine("After First String changed to {0}", IIf(IsNothing(x.MyFavoriteString), "Nothing", x.MyFavoriteString))
    x.MyFavoriteString = "Test"
    Console.WriteLine("After Second String changed to {0}", IIf(IsNothing(x.MyFavoriteString), "Nothing", x.MyFavoriteString))
Proves that the PropertyChanged event is only raised when the actual property value changes.
Before String change 'Nothing'
PropertyChanged: MyFavoriteString
After First String changed to Test
After Second String changed to Test
I would be very remiss to start pointing fingers at the Prism code regardless of the language used, and take another look at your implementation Peter.
Sep 4, 2014 at 8:37 AM
In your initial example, you have TWO properties declared not one. MyFavorite public property which is bindable works as you say. BindableBase sets the second NON-BINDABLE auto-property to the value. Obviously since the PrivateMyFavorite property does NOT raise the property changed event anything "Bound" to it will never be told it changes.
Sep 4, 2014 at 6:27 PM
Edited Sep 4, 2014 at 6:41 PM
Hi Allann,

Thank you for your patience and time. No offence! I don't want to criticize Prism or the people working so hard to provide perfect tools. But I also had the impression that this discussion forum is here to share experience, and that in fact is all I did. And asked fo help, because I cannot put my finger on the cause of my problem. I have provided samples and video's to illustrate my problem. I thought I was mild in my conclusion when I said "I should not get in trouble" because I highly trust Prism and it's quality. But just because of that I hope you can understand my despair and frustration when it appears to work for everyone else except for me. And I am prepared to try over and over again. And then share the results I get. That's all I have been doing. For about a week now.
So much for that and I seriously hope you nor anyone else felt (or feels) offended.


Then over to the code sample you have provided. I have put it over in a small Windows 8.1 solution that is comaparable in it's structure to the solution I have been working with so far. Because real life apps are not console proof-of-concepts. ;-) NO OFFENCE! As much as you want to settle this for once and for all, so much I love that too!

After all these confessions I'm happy to confirm to you that your approach works.
Eventhough I had to make ONE correction: in order to be able to bind the Name property of the MyFavoriteObject, it shouldn't be declared as Public (variable) but as a Property, so in a Windows 8.1 MVVM app, the TestItem object had to be declared as:
    Public Class TestItem
        Property Name As String
    End Class
Otherwise, it's not bindable as a property of MyFavoriteObject. Let's blame that on your first ever VB experimentations. It also shows how easy it is to make a small mistake with far reaching consequences. If I had put over this class without that modification, it would'nt have worked....

I will spend some time now to correct my code, to make it mimic this successfull approach

Thanks a lot!
Regards

BTW If you would be interested in the complete solution, let me know and I will publish it (in CodePlex or on OneDrive)