[MVVMbasics] Attribute-based bindable property declaration

All blog posts with a title that starts with [MVVMbasics] are related to the MVVMbasics framework. If you are only interested in my regular blog posts and not in MVVMbasics, ignore these. To list all articles covering MVVMbasics, go to http://mvvmbasics.mobilemotion.eu/documentation!

Previous versions of the MVVMbasics framework provided the Set method to help shorten bindable property declarations in Models and Viewmodels:

private string _someText;
public string SomeText
{
	get { return _someText; }
	set { Set(ref _someText, value); }
}

The Set method sets the property’s value and raises the PropertyChanged event if necessary. This allows the reduction of the setter method’s body to only one line, however the full property declaration still needs several lines of code since it is still necessary to define getter and setter method as well as the backing field manually.

MVVMbasics 2.2 finally supports the use of auto-properties as bindable properties. Properties defined in Models or Viewmodels that are marked with the MVVMbasics.Attributes.MvvmBindable attribute automatically raise the PropertyChanged event when their value is updated:

[MvvmBindable]
public string SomeText { get; set; }

While this significantly reduces code lines for bindable property declaration, it can still be simplified by using the [MvvmBindableProperties] attribute: In Viewmodels that contain many bindable properties, this attribute can be assigned to the Viewmodel class – in this case, all public properties defined within the Viewmodel class are treated as bindable, meaning that they will raise the PropertyChanged event when changed. To exclude single properties from this general rule, they can be marked with the [MvvmBindableIgnore] attribute:

[MvvmBindableProperties]
public class MyViewmodel : BaseViewmodel
{
	public string SomeText { get; set; }  // raises the PropertyChanged event
	
	public int SomeNumber { get; set; }  // raises the PropertyChanged event
	
	[MvvmBindableIgnore]
	public bool SomeInternalProperty { get; set; }  // does not raise the PropertyChanged event!
}

Please note that the [MvvmBindable...] attributes only work on properties that are defined within classes that inherit (directly or not) from the BaseModel or BaseViewmodel class! The reason for this limitation is that the automatic event raising mechanism that is responsible for all this magic relies on the NotifyPropertyChanged method which is defined by the BaseModel and BaseViewmodel classes.

Sometimes, bindable properties need to raise the PropertyChanged event more than once: The most typical case is a property that specifies only a getter method which returns a combination of several other properties:

public string FirstName { get; set; }

public string LastName { get; set; }

public string FullName
{
	get { return String.Format("{0} {1}", FirstName, LastName); }
}

The [MvvmBindable...] attributes even work in this case, since the underlying automatic event raising mechanism work in two iterations: First, all properties that don’t define a setter method are analyzed, and all the properties that are referenced in their getter methods are stored. In the second iteration, all properties that define setter methods are adapted, in order to raise their own PropertyChanged as well as all their dependent properties’ events! Note that for this to work, also the “read-only” properties (that only contain getter methods) need to be marked with the [MvvmBindable] attribute, or the whole class needs to be marked with the [MvvmBindableProperties] attribute.

public class MyViewmodel : BaseViewmodel
{
	[MvvmBindable]
	public string FirstName { get; set; }  // raises the PropertyChanged event for properties FirstName and FullName

	[MvvmBindable]
	public string LastName { get; set; }  // raises the PropertyChanged event for properties LastName and FullName

	[MvvmBindable]
	public string FullName
	{
		get { return String.Format("{0} {1}", FirstName, LastName); }
	}
}

Of course, the conventional way of creating a backing field and calling the Set method inside the property’s setter method is still available. For complex property declarations where the automatic event raising mechanism fails, you can still rely on this approach. Also if you like to automatically call a certain action before or after the property update, the Set method might be the better solution. All of the options it offers is documented in the article New version 2.0 features #2: Simplified Data Binding with more flexibility.