Best way to write MVVM boilerplate code?

I recently discovered that I wrote a lot of MVVM code templates and am wondering if there is a fun way around this? I already use the ViewModelBase class, which implements INotifyPropertyChanged , but this does not solve the problem of having to write all the access code, etc. Perhaps by writing a custom attribute that does this, or through a template system?

 public MyClass : ViewModelBase { private int someVariable; public int SomeVariable { get { return this.someVariable; } set { this.someVariable = value; this.NotifyPropertyChanged("SomeVariable"); } } } 
+6
source share
5 answers

I have a snippet that I use to create my view model properties. This snippet uses the notation Expression<Func<T>> , which other commentators have hinted at.

 <?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 for hard canceling property notification and validation for me.

Using:

  • propvm type
  • Press Tab twice
  • Fill in the selected field and click the tab to go to the next.

Walkthrough: Creating a Code Snippet

+4
source

Aspect Oriented Programming (AOP) is a way to reduce the amount of such template code. The frame that is widely known is PostSharp . There is also a free version of Express.
You use attributes (either in classes directly, or as multicast to all points of the code that satisfy a certain set of conditions) to mark the places where the code should be integrated, and PostSharp in the implementations at build time. You can find an example for implementing INotifyPropertyChanged here .
The AOP-based approach (no matter what structure you use) has the advantage that you can subsequently change the implementation and that these changes are reflected in the existing code base. It is also possible to apply aspects to a large number of existing classes.

+1
source

Wow ... that many answers in the comments and not so much in the answers. As an alternative to the beautiful new CallerMemberNameAttribute attribute, what about Visual Studio Macros ? I have several of them that fully implement all my interfaces (both user and .NET) for me with a single click.

The downside of using macros:

You write them with visual basic
It may take some time to write a long page. They may contain errors such as any code.

Macro use surface:

You can "record" simple macros when entering a name. You can create complex macros that can work with the current context.
They can write thousands of words with the click of a mouse button.

For example, I can create a class file that defines only the class name, base class and / or interfaces. After declaring private member variables, I can run my own macro, and it will read the names and types of variables and generate the constructors, properties, and all methods needed for the base classes and / or interfaces used. However, this macro is nearly 600 lines long.

0
source

First of all, as already mentioned, use the code snippet to create the code for you. Then there are several libraries that can help you, or AOP.

And here is something that I used for some time in applications where raw ui performance on simple controls does not matter: a helper class with Dictionary<string,object> for storing actual internal resources and methods for getting / setting properties of any type, accepting an expression as an argument to avoid using string literals. When using this property, the property is reduced to

 public int SomeProperty { get { return properties.Get( model => model.SomeProperty ); } set { properties.Set( model => model.SomeProperty, value ); } } 

also that calling Set returns true when the value really changes, as this is often useful.

Here is some code, with the usual warning about "using at your own risk." You just need an implementation of NotifyPropertyChangedHelper, but it can be easily found (for example, a network search for the “propertychanged helper”, it’s pretty sure that it was also hosted on SO)

 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 } 
0
source

Use a snippet like "mvvmprop". There are many available there that are already written for this purpose, including the implementation of MVVM Lite.

0
source

Source: https://habr.com/ru/post/958313/


All Articles