Data bound view elements still not updating despite the use of Fody PropertyChanged package in Windows Phone 8 app?

839 views Asked by At

I have a C# Windows Phone 8 MVVM app with the Fody PropertyChanged package installed. I have added the ImplementPropertyChanged directive before the class declaration:

[CompilerGenerated]
[GeneratedCode("Radarc", "4.0")]
[ImplementPropertyChanged]
public partial class MilitaryRobots_VideosViewModel : ViewModelsBase.VMBase, IViewModels.IMilitaryRobots_VideosViewModel, INotifyPropertyChanged

I have the following two properties in the class that I bind View elements to:

    private Visibility _showDetailsVideo = Visibility.Collapsed;

    public Visibility ShowDetailsVideo 
    { 
        get
        {
            return this._showDetailsVideo;
        }

        set
        {
            this._showDetailsVideo = value;
            this.ShowMainScreen = value == Visibility.Visible ? Visibility.Collapsed : Visibility.Visible;
        }
    }

    private Visibility _showMainScreen = Visibility.Visible;

    /// <summary>
    /// Never set this property, instead set ShowDetailsVideo instead.
    /// </summary>
    public Visibility ShowMainScreen
    {
        get
        {
            return this._showMainScreen;
        }

        private set
        {
            this._showMainScreen = value;
        }
    }

One View element's Visibility property is bound to the View Model's ShowDetailsVideo property. Another View element's Visibility property is bound to the View Model's ShowMainScreen property. At runtime both property getters are accessed indicating that the pair of bound View elements are accessing the properties at least once. Also, the two View elements do have the proper Visibility states. However if I change the ShowDetailsVideo property at runtime, the setters are accessed but not the getters, indicating the wiring between the properties and the view element properties isn't working, despite my use of the Fody PropetyChanged package. The property access behavior is the same as if the Fody package wasn't even there.

How can I fix this and get it working so the view elements pair of Visibility properties are updated properly at runtime? I thought the Fody PropertyChanged package was supposed to make implementing property change notification unnecessary.

1

There are 1 answers

0
Robert Oschler On

I am adding this answer because this problem cost me several hours to hunt down and fix. I am marking the answer as community wiki because I am not seeking credit for it, only to save someone else the trouble I went through diagnosing it.

Below is the corrected View Model code to make the property changed notifications work properly. The View was not updating when bindable properties in the View Model were changed because I was not calling the base SetProperty() method in the property setter, instead I was only doing a direct assignment so a property changed notification was not triggered. You can see this in the property setter in my original post. Simply adding the SetProperty() call fixed everything.

So if your View Model class descends from a class like BindableBase (see below), you do not need the Fody PropertyChanged plugin at all, but make sure you are calling SetProperty() in your property setters instead of doing a direct assignment to the data member backing the property.

Updated property setters/getters

    private Visibility _showDetailsVideo = Visibility.Collapsed;

    public Visibility ShowDetailsVideo 
    { 
        get
        {
            return this._showDetailsVideo;
        }

        set
        {
            SetProperty(ref this._showDetailsVideo, value);
            this.ShowMainScreen = value == Visibility.Visible ? Visibility.Collapsed : Visibility.Visible;
        }
    }

    private Visibility _showMainScreen = Visibility.Visible;

    /// <summary>
    /// Never set this property, instead set ShowDetailsVideo instead.
    /// </summary>
    public Visibility ShowMainScreen
    {
        get
        {
            return this._showMainScreen;
        }

        private set
        {
            SetProperty(ref this._showMainScreen, value);
        }
    }

BindableBase class that my View Model descends from

/// <summary>
/// Abstraction of data-binder that notifies properties changes to the suitable View.
/// </summary>
public abstract class BindableBase : INotifyPropertyChanged
{
    /// <summary>
    /// Event launched when a property of the bindable object has changed.
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;

    /// <summary>
    /// Sets the value of the binded property.
    /// </summary>
    /// <typeparam name="T">The generic type.</typeparam>
    /// <param name="storage">The type of the property.</param>
    /// <param name="value">The value of the property.</param>
    /// <param name="propertyName">The name of the property.</param>
    /// <returns>A boolean indicating the success of the assignation.</returns>
    protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName]String propertyName = null)
    {
        if (Equals(storage, value)) return false;

        storage = value;
        OnPropertyChanged(propertyName);
        return true;
    }

    /// <summary>
    /// Event handler for the PropertyChanged event.
    /// </summary>
    /// <param name="propertyName">The name of the property that has changed.</param>
    protected void OnPropertyChanged(string propertyName = null)
    {
        //if (Debugger.IsAttached)
        //    Debug.WriteLine("Property changed: " + propertyName);

        var eventHandler = PropertyChanged;
        if (eventHandler != null)
            eventHandler(this, new PropertyChangedEventArgs(propertyName));
    }

    /// <summary>
    /// Initializes the bindable object.
    /// </summary>
    /// <param name="parameters">Dictionary with the parameters.</param>
    public virtual void Initialize(IDictionary<string, string> parameters)
    {

    }
}