I have found myself recently writing a lot of boilerplate MVVM code and wonder if there is a fancy way to get around writing it all? I already use a ViewModelBase
class that implements INotifyPropertyChanged
but that doesnt solve the problem of having to write all the accessor code etc. Perhaps by writing a custom attribute that does this, or via a templating system?
public MyClass : ViewModelBase
{
private int someVariable;
public int SomeVariable
{
get
{
return this.someVariable;
}
set
{
this.someVariable = value;
this.NotifyPropertyChanged("SomeVariable");
}
}
}
I have a snippet that i use to create my view model properties. This particular snippet uses the Expression<Func<T>>
notation that other commenters have hinted upon.
<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
<Title>View Model Property</Title>
<Description>
Declares a property and member suitable for Viewmodel implementation.
</Description>
<HelpUrl>
</HelpUrl>
<Shortcut>propvm</Shortcut>
</Header>
<Snippet>
<Declarations>
<Literal Editable="true">
<ID>propname</ID>
<ToolTip>Property Name</ToolTip>
<Default>Name</Default>
<Function>
</Function>
</Literal>
<Literal Editable="true">
<ID>type</ID>
<ToolTip>Property type.</ToolTip>
<Default>Type</Default>
<Function>
</Function>
</Literal>
<Literal Editable="true">
<ID>init</ID>
<ToolTip>Member initialisation</ToolTip>
<Default>null</Default>
<Function>
</Function>
</Literal>
</Declarations>
<Code Language="csharp" Kind="type decl"><![CDATA[public $type$ $propname$
{
get { return m_$propname$; }
set
{
m_$propname$ = value;
base.OnPropertyChanged(() => $propname$);
}
} $type$ m_$propname$ = default($type$);$end$]]></Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
Note the call to base.PropertyChanged()
. I have a ViewModelBase
class to do the heavy lifting of property notification and validation for me.
Usage is this:
- Type
propvm
- Hit TAB twice
- Fill in the highlighted field and press tab to flip to the next one!
Walkthrough : Creating a code snippet
Aspect oriented programming (AOP) is a way to reduce the amount of such boilerplate code. A framework that is widely known is PostSharp. There also is a free Express edition.
You use attributes (either on the classes directly or as a multicast to all points in code that satisfy a specific set of conditions) to mark the spots where the code should be integrated and PostSharp weaves in the implementations during build. You can find an example for the implementation of INotifyPropertyChanged here.
An AOP based approach (no matter which framework you use) has the advantage that you can change the implementation afterwards and that these changes are reflected in the existing code base. It is also possible to apply the aspects to a big number of already existing classes.
Wow... that's a lot of answering in the comments and not so much in the answers. As an alternative to the lovely new CallerMemberNameAttribute
attribute, how about Visual Studio Macros? I have a number of these that fully implement all of my interfaces (both custom and .NET) for me at the click of a mouse button.
Downside to using Macros:
You write them using Visual Basic
It can take a while to write a long one
They can contain errors like any code
Upside to using Macros:
You can 'record' simple Macros as you type
You can build up complex Macros that can work with current context
They can write thousands of words at the click of a mouse button
For example, I can create a class file, defining just the class name, base class and/or interfaces. After declaring the private member variables, I can run my custom Macro and it will read the names and types of the variables and generate constructors, properties and all methods required by the base classes and/or interfaces used. However, this particular Macro is almost 600 lines long.
First of all and as mentioned already, use a snippet to create the code for you.
Then there are a couple of libraries that can help you with it, or AOP.
And here's something I've been using for a while in applications where raw ui performance on simple controls is irrelevant: a helper class with a Dictionary<string,object>
to hold the actual property backends, and methods to get/set properties of any type, taking an expression as argument in order to avoid using string literals. When using this, a property comes down to
public int SomeProperty
{
get { return properties.Get( model => model.SomeProperty ); }
set { properties.Set( model => model.SomeProperty, value ); }
}
also that Set
call returns true when the value really changed as that is often useful.
Here's some code, with the usual 'use at own risk' etc warning. You just need a NotifyPropertyChangedHelper implementation but that can be found easily (search the net for 'propertychanged helper' for instance, pretty sure it was posted on SO as well)
public class NotifyPropertyChangedMap<T> where T : INotifyPropertyChanged
{
#region Fields
private readonly T propertyContainer;
private readonly Dictionary<string, object> properties;
#endregion
#region Constructors
public NotifyPropertyChangedMap( T propertyContainer )
{
Contract.Requires<ArgumentNullException>( propertyContainer != null, "propertyContainer" );
this.propertyContainer = propertyContainer;
this.properties = new Dictionary<string, object>();
}
#endregion
#region Get and Set
public Property Get<Property>( Expression<Func<T, Property>> expression )
{
var propName = NotifyPropertyChangedHelper.GetPropertyName( expression );
if( !properties.ContainsKey( propName ) )
properties.Add( propName, GetDefault<Property>() );
return (Property) properties[ propName ];
}
public bool Set<Property>( Expression<Func<T, Property>> expression, Property newValue )
{
var propName = NotifyPropertyChangedHelper.GetPropertyName( expression );
if( !properties.ContainsKey( propName ) )
{
properties.Add( propName, newValue );
propertyContainer.RaisePropertyChangedEvent( propName );
}
else
{
if( EqualityComparer<Property>.Default.Equals( (Property) properties[ propName ], newValue ) )
return false;
properties[ propName ] = newValue;
propertyContainer.RaisePropertyChangedEvent( propName );
}
return true;
}
#endregion
#region Implementation
private static Property GetDefault<Property>()
{
var type = typeof( Property );
return (Property) ( type.IsValueType ? Activator.CreateInstance( type ) : null );
}
#endregion
}
Use a snippet like "mvvmprop" There are many out there that are available already written just for this purpose, including MVVM Lite's implementation.