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

时间:2013-11-18 15:22:47

标签: c# wpf silverlight mvvm inotifypropertychanged

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

INotifyPropertyChanged

5 个答案:

答案 0 :(得分:5)

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

<?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>

请注意对base.PropertyChanged()的通话。我有一个ViewModelBase课程来为我做繁重的财产通知和验证。

用法是:

  1. 输入propvm
  2. 两次点击 TAB
  3. 填写突出显示的字段,然后按Tab键翻转到下一个字段!
  4. Walkthrough : Creating a code snippet

答案 1 :(得分:1)

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

答案 2 :(得分:0)

哇...在评论中有很多回答而在回答中没有那么多回答。作为可爱的新CallerMemberNameAttribute属性的替代方案,Visual Studio Macros怎么样?我有很多这些可以通过点击鼠标按钮完全实现我的所有接口(自定义和.NET)。

使用宏的缺点:

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

之类的错误

使用宏的好处:

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

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

答案 3 :(得分:0)

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

这是我在应用程序中使用了一段时间,其中简单控件上的原始ui性能无关紧要:一个用Dictionary<string,object>来保存实际属性后端的辅助类,以及获取/设置属性的方法任何类型的,将表达式作为参数,以避免使用字符串文字。使用它时,属性归结为

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

答案 4 :(得分:0)

使用像“mvvmprop”这样的片段有许多已经可用的内容,包括MVVM Lite的实现。