我发现自己最近编写了大量的样板MVVM代码,并想知道是否有一种奇特的方式可以解决所有问题?我已经使用了一个实现ViewModelBase
的{{1}}类,但这并没有解决必须编写所有访问者代码等的问题。也许是通过编写一个自定义属性来执行此操作,还是通过模板系统?< / p>
INotifyPropertyChanged
答案 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
课程来为我做繁重的财产通知和验证。
用法是:
propvm
答案 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的实现。