Reducing MVVM Light Viewmodel Code with Fody Property Dependencies and Custom Property Changed Methods

In other previous articles I’ve written about Fody and this article we’ll see how we can use the PropertyChanged.Fody addin with MVVM Light viewmodels.

Windows Store app screenshot

The preceding screenshot shows the app in action: a name TextBox is twoway data-bound to the viewmodel, when a different name is typed, the TextBlock shows the uppercase version.

The user can also type a color into the color box and a bit of reflection happens to convert this string to a color from the Colors class.

Windows Store app screenshot with different bg color

The following code shows the (non Fody-fied) viewmodel:

class HandWrittenMainViewModel : ViewModelBase
{
    private string _name = "Jason";
    public string Name
    {
        get { return _name; }
        set
        {
            Set(Name, ref _name, value);

            NameChanged();
        }
    }

    private void NameChanged()
    {
        RaisePropertyChanged("UpperName");
    }

    
    public string UpperName
    {
        get
        {
            return Name.ToUpperInvariant();  
        }
    }

    private string _faveColor = "Black";
    public string FaveColor
    {
        get { return _faveColor; }
        set
        {
            Set(FaveColor, ref _faveColor, value);

            FaveColorChanged();
        }
    }

    private void FaveColorChanged()
    {
        var m = typeof (Colors).GetTypeInfo().GetDeclaredProperty(FaveColor);
        var c = (Color) m.GetValue(null);
        BgBrush = new SolidColorBrush(c);
    }


    private Brush _bgBrush;
    public Brush BgBrush
    {
        get { return _bgBrush; }
        set
        {
            if (value == _bgBrush)
            {
                return;
            }

            _bgBrush = value;

            RaisePropertyChanged();
        }
    }
}

So here the properties Name, UpperName, and BgBrush are all hand-coded and manually call MVVM Light’s Set method to create notifications, etc.

Also notice in the Name setter we’re manually specifying that the UpperName should also change (raise a notification event so the view knows to update); in this way UpperName change notification is dependent upon Name property changes.

We also need to update the BgBrush property when the user types a color that’s bound to the FaveColor property.

The following code shows what a refactored viewmodel could look like after installing the PropertyChanged.Fody NuGet package:

class FodyfiedMainViewModel : ViewModelBase
{
    public FodyfiedMainViewModel()
    {
        Name = "Jason";
        FaveColor = "Black";
    }
    

    public string Name { get; set; }

    public string UpperName
    {
        get
        {
            return Name.ToUpperInvariant();
        }
    }

    public string FaveColor { get; set; }

    private void OnFaveColorChanged()
    {
        var m = typeof(Colors).GetTypeInfo().GetDeclaredProperty(FaveColor);
        var c = (Color)m.GetValue(null);
        BgBrush = new SolidColorBrush(c);
    }

    public Brush BgBrush { get; set; }
}

Here we’ve gone from about 73 lines of code down to just 38.

Notice that for the “dependent” UpperName property we’re no longer manually creating a notification event when the Name property changes – Fody is clever enough to notice that we’re referencing the Name property in the getter and automatically creates a notification as we can see in the following decompiled code snippet:

public string Name
{
    get
    {
        return this.u003cNameu003ek__BackingField;
    }
    set
    {
        if (String.Equals(this.u003cNameu003ek__BackingField, value, 4))
        {
            return;
        }
        this.u003cNameu003ek__BackingField = value;
        this.RaisePropertyChanged("UpperName");
        this.RaisePropertyChanged("Name");
    }
}

 

Because we want to create a new BgBrush brush when the user types a new FaveColor we need to hook into the setter. To do this we can use a convention and create a method named On[PROPERTYNAME]Changed. Here we’ve created the OnFaveColorChanged method. Fody will call this method every time the FaveColor property is set. Again if we look at the decompiled code we can see a call to the method in the generated setter:

public string FaveColor
{
    get
    {
        return this.u003cFaveColoru003ek__BackingField;
    }
    set
    {
        if (String.Equals(this.u003cFaveColoru003ek__BackingField, value, 4))
        {
            return;
        }
        this.u003cFaveColoru003ek__BackingField = value;
        this.OnFaveColorChanged();
        this.RaisePropertyChanged("FaveColor");
    }
}

For a list of the other Fody addins available check out the GitHub project site.

To learn more about how Fody works, how to use the available addins, and even how to create your own check out my Automatic .NET Code Weaving With Fody Pluralsight course.

Comments (3) -

  • Mike C

    7/11/2014 6:07:11 AM | Reply

    This looks quite nice, but I can't help but think that ReSharper would then complain that private void OnFaveColorChanged() is not referenced anywhere, and would grey it out, suggesting removal.

  • Jason

    7/11/2014 12:36:15 PM | Reply

    Correct Mike, you could do something like the following to disable:

    // ReSharper disable UnusedMember.Local
            private void OnFaveColorChanged()
    // ReSharper restore UnusedMember.Local

  • Simon Cropp

    7/16/2014 4:49:18 AM | Reply

    Mike

    You should add a test that executes OnFaveColorChanged and verifies the results then r# should not complain

Add comment

Loading