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:

More...

Say Goodbye to Boring INotifyPropertyChanged Implementation in Universal Windows Apps with Fody

We need to implement INotifyPropertyChanged to allow bindings to be updated. For example in a simple viewmodel to add 2 numbers:

namespace UniFodyDemo
{    
    internal class CalculatorViewModel : INotifyPropertyChanged
    {
        private ICommand _addCommand;
        private string _firstNumber;
        private string _secondNumber;

        public CalculatorViewModel()
        {
            FirstNumber = "5";
            SecondNumber = "10";
            Result = "";

            AddCommand = new RelayCommand(Add);
        }


        // Use strings to simplify demo code (so no val converter)
        public string FirstNumber
        {
            get { return _firstNumber; }
            set
            {
                _firstNumber = value;
                OnPropertyChanged();
            }
        }

        public string SecondNumber
        {
            get { return _secondNumber; }
            set
            {
                _secondNumber = value;
                OnPropertyChanged();
            }
        }

        public string Result { get; set; }

        public ICommand AddCommand
        {
            get { return _addCommand; }
            private set
            {
                _addCommand = value;
                OnPropertyChanged();
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void Add(object obj)
        {
            var a = int.Parse(FirstNumber);
            var b = int.Parse(SecondNumber);

            Result = (a + b).ToString();
        }

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

There’s more code here than we’d need if we didn’t have to implement INotifyPropertyChanged. Really the important things are the 3 properties that we bind to and the add command / method.

The XAML in both the Windows Store app and Windows Phone app looks like:

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <StackPanel Width="200">
        <TextBlock Text="{Binding FirstNumber, Mode=TwoWay}"></TextBlock>
        <TextBlock Text="{Binding SecondNumber, Mode=TwoWay}"></TextBlock>
        <Button Command="{Binding AddCommand}">Add</Button>
        <TextBlock Text="{Binding Result, Mode=TwoWay}"></TextBlock>
    </StackPanel>
</Grid>

Without implementing INotifyProperty changed, clicking the Add button won’t be of much use, we wont see the result.

The solution looks like the following, the shared project contains the viewmodel.

image

It would be great not have to write this same INotifyProperty stuff for everything we want to bind to/from. Using a NuGet package called PropertyChanged.Fody we can achieve this.

First this package needs to be installed into both the Windows Store and Windows Phone app projects. This is because the shared code in the viewmodel isn’t compiled in that shared project, rather the source code is compiled individually in both the Store/Phone projects.

Now the viewmodel can be simplified:

namespace UniFodyDemo
{
    [ImplementPropertyChanged]
    class CalculatorViewModel
    {
        public CalculatorViewModel()
        {
            FirstNumber = "5";
            SecondNumber = "10";
            Result = "";

            AddCommand = new RelayCommand(Add);
        }

        private void Add(object obj)
        {
            var a = int.Parse(FirstNumber);
            var b = int.Parse(SecondNumber);

            Result = (a + b).ToString();
        }
        

        // Use strings to simplify demo code (so no val converter)
        public string FirstNumber { get; set; }
        public string SecondNumber { get; set; }
        public string Result { get; set; }

        public ICommand AddCommand { get; private set; }
    }
}

Notice the [ImplementPropertyChanged] attribute which means INotifyPropertyChanged will be automatically implemented for us. Notice that it’s much easier to see what’s essential in the viewmodel without all the noise of INotifyPropertyChanged.

If we decompile the Windows store app we can see the implementation:

namespace UniFodyDemo
{
    internal class CalculatorViewModel : INotifyPropertyChanged
    {
        public ICommand AddCommand
        {
            get
            {
                return this.u003cAddCommandu003ek__BackingField;
            }
            private set
            {
                if (this.u003cAddCommandu003ek__BackingField == value)
                {
                    return;
                }
                this.u003cAddCommandu003ek__BackingField = value;
                this.OnPropertyChanged("AddCommand");
            }
        }

        public string FirstNumber
        {
            get
            {
                return this.u003cFirstNumberu003ek__BackingField;
            }
            set
            {
                if (String.Equals(this.u003cFirstNumberu003ek__BackingField, value, 4))
                {
                    return;
                }
                this.u003cFirstNumberu003ek__BackingField = value;
                this.OnPropertyChanged("FirstNumber");
            }
        }

        public string Result
        {
            get
            {
                return this.u003cResultu003ek__BackingField;
            }
            set
            {
                if (String.Equals(this.u003cResultu003ek__BackingField, value, 4))
                {
                    return;
                }
                this.u003cResultu003ek__BackingField = value;
                this.OnPropertyChanged("Result");
            }
        }

        public string SecondNumber
        {
            get
            {
                return this.u003cSecondNumberu003ek__BackingField;
            }
            set
            {
                if (String.Equals(this.u003cSecondNumberu003ek__BackingField, value, 4))
                {
                    return;
                }
                this.u003cSecondNumberu003ek__BackingField = value;
                this.OnPropertyChanged("SecondNumber");
            }
        }

        public CalculatorViewModel()
        {
            this.FirstNumber = "5";
            this.SecondNumber = "10";
            this.Result = "";
            this.AddCommand = new RelayCommand(new Action<object>(this, CalculatorViewModel.Add));
        }

        private void Add(object obj)
        {
            int num = Int32.Parse(this.FirstNumber);
            int num1 = Int32.Parse(this.SecondNumber);
            this.Result = (num + num1).ToString();
        }

        public virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler propertyChangedEventHandler = this.PropertyChanged;
            if (propertyChangedEventHandler != null)
            {
                propertyChangedEventHandler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}

So not only with Universal projects can we share code via the shared code project, adding Fody into the mix is even more awesome.

For a list of available addins or to contribute (or even create your own addin) check out the GitHub project site.

Also to learn more about Fody feel free to check out my Pluralsight course.

Write Less Repetitive Boilerplate Code with Fody

My newest Pluralsight course on Fody was just released.

Fody is a tool that frees us up from having to write repetitive boilerplate code. For example we can automate IDisposable implementation or automatically add Equals(), GetHashCode() and equality operators.

Fody is not one tool, but a collection of individual “addins” around the core Fody, with the core GitHub members: Simon Cropp, Rafał Jasica, and Cameron MacFarland.

Automatically Implementing Equality

As an example of what’s possible with Fody, we can auto-implement equality.

So first off we install the Equals Fody addin via NuGet:

PM> Install-Package Equals.Fody

Now we can add the [Equals] attribute to indicate that we want to auto-implement equality.

We can opt-out specific properties so they won’t be considered during equality by applying the [IgnoreDuringEquals] attribute.

We can also provide custom equality logic by creating a method and decorating it with the [CustomEqualsInternal] attribute. So for example if either altitude is –1 then consider altitudes equal.

The following code shows these attributes in action:

[Equals]
public class Location
{
    [IgnoreDuringEquals] 
    public int Altitude { get; set; }
    
    public int Lat { get; set; }
    public int Long { get; set; }

    [CustomEqualsInternal]
    private bool CustomEqualsLogic(Location other)
    {
        // this method is evaluated if the other auto-equal properties are equal

        if (this.Altitude == other.Altitude)
        {
            return true;
        }

        if (this.Altitude == -1 || other.Altitude == -1)
        {
            return true;
        }

        return false;
    } 
}

For a list of available addins or to contribute (or even create your own addin) check out the GitHub project site.

To learn more about how Fody works, how to use some of the available addins, and how to create your own check out my Pluralsight course.

Write Less MVVM ViewModel Boilerplate Code with T4

Although code snippets can make creating our initial viewmodels easier (properties, commands,etc.) it’s still tantamount to boilerplate code. Obviously the actions that happen when a command is executed is not boilerplate, but the actual definition is.

T4 templates are built into Visual Studio and allow us to define templates that are a mix of literal output (such as HTML tags) and C# code.

We can for example create a C# for loop around some literal output, e.g. “Hello World” to output it 10 times. For more info on T4, check out MSDN.

T4 for View Model Code Generation

Rather than hand-coding viewmodels, we can define a T4 template. In this template we are able to define the view models we want generating – included both commands and properties that we want to have on those view models.

The implementation in this article creates a new abstract base class for each view model that contains our commands and properties, in addition to a command init method to create and wire-up new MVVM Light RelayCommands along with can execute hooks.

Once T4 has generated these base class view models, we inherit from them and a constructor that calls the base class’s InitCommands method.

The sample application bind some text and a button:

before clicking button

When you click the button the bound Person in the viewmodel is updated and the command is disabled:

after clicking button

 

The actual viewmodel code looks like this:

using SampleWpfApplication.Model;

namespace SampleWpfApplication.ViewModel
{
    class MainViewModel : MainViewModelBase
    {
        public MainViewModel()
        {
            InitCommands();
        }

        protected override void ExecuteLoad()
        {
            Who = new Person {Name="Jason"};
            LoadCommand.RaiseCanExecuteChanged();
        }

        protected override bool CanExecuteLoad()
        {
            return Who == null;
        }
    }
}

Note it derives from MainViewModelBase which is the generated code.

Also note there’s no Person property (called “Who”) and no RelayCommand defined.

We’ve overridden a couple of methods from the base class to get the behaviour we want and also called InitCommands in the constructor.

The fragment of the T4 template that defines the viewmodels looks like this:

/// <summary>
/// Make changes to this class to define what view models you want generating
/// </summary>
public  static class ViewModelGeneratorSettings
{   
    // ********** Which name space the view model classes will live in
    public const string OutputNameSpace = "SampleWpfApplication.ViewModel";


    public static List<ViewModelDefinition> ViewModelDefinitions
    {
        get
        {
            return new List<ViewModelDefinition>()
                   {
                       // Define your view models here
                       new ViewModelDefinition
                       {
                           Name = "MainViewModel",
                           Properties =
                           {
                               Tuple.Create("Who", "Person"), // here Who is the name of the command prop, Person is the type
                               //Tuple.Create("NextTopic", "Topic"),
                               //Tuple.Create("CurrentTopicTimeRemaining", "TimeSpan"),
                               //Tuple.Create("TotalTimeRemaining", "TimeSpan"),
                               //Tuple.Create("IsPlaying", "bool") // here IsPlaying is the name of the command prop, bool is the type
                           },
                           Commands =
                           {
                               "Load", // Name of the commands
                               //"Pause"
                           }
                       },
                       new ViewModelDefinition
                       {
                           Name = "AnotherViewModel",
                           Properties =
                           {
                               Tuple.Create("SomeProperty", "int"),
                           },
                           Commands =
                           {
                               "A",
                               "B"
                           }
                       }, // etc.
                   };
        }
    }
}

To create new viewmodels we just add new ViewModelDefinitions and specify what properties and commands we want – currently property types are specified as strings rather than actual types.

To get started and see it in action, download the sample application from GitHub and see how it fits together. The full template is here as well.

While the examples here relate to MVVM Light, the concept could be used with other frameworks.