编写MVVM样板代码的更好方法是什么?

我发现自己最近编写了大量的样板MVVM代码,并想知道是否有一种奇特的方式可以解决所有问题? 我已经使用了实现INotifyPropertyChangedViewModelBase类,但这并没有解决必须编写所有访问者代码等问题。也许是通过编写一个自定义属性来执行此操作,还是通过模板系统?

 public MyClass : ViewModelBase { private int someVariable; public int SomeVariable { get { return this.someVariable; } set { this.someVariable = value; this.NotifyPropertyChanged("SomeVariable"); } } } 

我有一个片段,用于创建我的视图模型属性。 此特定代码段使用其他评论者暗示的Expression>表示法。

    
Expansion View Model Property Declares a property and member suitable for Viewmodel implementation. propvm
propname Property Name Name type Property type. Type init Member initialisation null $propname$); } } $type$ m_$propname$ = default($type$);$end$]]>

请注意对base.PropertyChanged()的调用。 我有一个ViewModelBase类来为我做繁重的属性通知和validation。

用法是这样的:

  1. propvm
  2. 点击TAB两次
  3. 填写突出显示的字段,然后按Tab键翻转到下一个字段!

演练:创建代码段

面向方面编程(AOP)是一种减少此类样板代码量的方法。 众所周知的框架是PostSharp 。 还有免费的Express版本。
您可以使用属性(在类上直接或作为多播到代码中满足特定条件的所有点)来标记代码应该集成的位置,PostSharp在构建期间在实现中编织。 您可以在此处找到实现INotifyPropertyChanged的示例。
基于AOP的方法(无论您使用哪种框架)都具有以下优势:您可以在之后更改实现,并且这些更改将反映在现有代码库中。 也可以将这些方面应用于大量已存在的类。

哇…这些评论中有很多回答而不是答案。 作为可爱的新CallerMemberNameAttribute属性的替代, Visual Studio宏如何? 我有很多这些可以通过点击鼠标按钮完全实现我的所有接口(自定义和.NET)。

使用宏的缺点:

您使用Visual Basic编写它们
写一个很长的一段时间可能需要一段时间
它们可能包含任何代码错误

使用宏的好处:

您可以在键入时 “记录”简单的宏
您可以构建可以使用当前上下文的复杂宏
只需单击鼠标按钮,它们就可以编写数千个单词

例如,我可以创建一个类文件,只定义类名,基类和/或接口。 在声明私有成员变量之后,我可以运行我的自定义宏,它将读取变量的名称和类型,并生成构造函数,属性以及所使用的基类和/或接口所需的所有方法。 但是,这个特殊的宏几乎是600行。

首先,如上所述,使用代码片段为您创建代码。 然后有几个库可以帮助你,或AOP。

这是我在应用程序中一直使用的东西,其中简单控件上的原始ui性能无关紧要:带有Dictionary的helper类来保存实际的属性后端,以及获取/设置任何属性的方法type,将表达式作为参数,以避免使用字符串文字。 使用它时,属性归结为

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

当值真正改变时, Set调用返回true,因为这通常很有用。

这里有一些代码,通常是“自担风险”等警告。 你只需要一个NotifyPropertyChangedHelper实现,但是可以很容易地找到它(例如在网上搜索’propertychanged helper’,非常确定它也是在SO上发布的)

 public class NotifyPropertyChangedMap where T : INotifyPropertyChanged { #region Fields private readonly T propertyContainer; private readonly Dictionary properties; #endregion #region Constructors public NotifyPropertyChangedMap( T propertyContainer ) { Contract.Requires( propertyContainer != null, "propertyContainer" ); this.propertyContainer = propertyContainer; this.properties = new Dictionary(); } #endregion #region Get and Set public Property Get( Expression> expression ) { var propName = NotifyPropertyChangedHelper.GetPropertyName( expression ); if( !properties.ContainsKey( propName ) ) properties.Add( propName, GetDefault() ); return (Property) properties[ propName ]; } public bool Set( Expression> expression, Property newValue ) { var propName = NotifyPropertyChangedHelper.GetPropertyName( expression ); if( !properties.ContainsKey( propName ) ) { properties.Add( propName, newValue ); propertyContainer.RaisePropertyChangedEvent( propName ); } else { if( EqualityComparer.Default.Equals( (Property) properties[ propName ], newValue ) ) return false; properties[ propName ] = newValue; propertyContainer.RaisePropertyChangedEvent( propName ); } return true; } #endregion #region Implementation private static Property GetDefault() { var type = typeof( Property ); return (Property) ( type.IsValueType ? Activator.CreateInstance( type ) : null ); } #endregion } 

使用像“mvvmprop”这样的片段有很多可用的内容,仅用于此目的,包括MVVM Lite的实现。