我目前正在设置我的新项目,并且想知道如何实现我的ViewModel类确实具有INotifyPropertyChanged支持,而不必亲自手动编码所有属性。
我查看了AOP框架,但我认为他们只会用另一个依赖项来炸毁我的项目。
所以我考虑用T4生成属性实现。
设置是这样的:我有一个ViewModel类,它只声明了它的Properties背景变量,然后我使用T4从它生成属性实现。
例如,这将是我的ViewModel:
public partial class ViewModel
{
private string p_SomeProperty;
}
然后T4将遍历源文件并查找名为“p_”的成员声明并生成如下文件:
public partial class ViewModel
{
public string SomeProperty
{
get
{
return p_SomeProperty;
}
set
{
p_SomeProperty= value;
NotifyPropertyChanged("SomeProperty");
}
}
}
这种方法有一些优点,但我不确定它是否真的有效。因此,我想在StackOverflow上发布我的想法作为一个问题,以获得一些反馈,也许一些建议如何更好/更容易/更安全。
答案 0 :(得分:7)
Here's a great post by Colin Eberhardt通过使用EnvDTE直接从Visual Studio检查自定义属性,从T4生成依赖项属性。由于帖子包含简单的实用程序方法来浏览代码节点,因此将其调整为检查字段并适当生成代码应该不难。
请注意,在VS中使用T4时,不应在自己的程序集上使用Reflection,否则它们将被锁定,您必须重新启动Visual Studio才能重建。
答案 1 :(得分:3)
有很多方法可以给这只猫上皮。
我们一直在用PostSharp来注入INotifyProperty样板。这似乎工作得很好。
话虽如此,T4没有理由不起作用。
我同意Dan的观点,你应该创建OnPropertyChanged的基类实现。
您是否考虑过仅使用代码段?它会为你编写样板文件。唯一的缺点是,如果您想在以后更改属性名称,它将不会自动更新。
<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>propin</Title>
<Shortcut>propin</Shortcut>
<Description>Code snippet for property and backing field with support for INotifyProperty</Description>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>type</ID>
<ToolTip>Property type</ToolTip>
<Default>int</Default>
</Literal>
<Literal>
<ID>property</ID>
<ToolTip>Property name</ToolTip>
<Default>MyProperty</Default>
</Literal>
</Declarations>
<Code Language="csharp">
<![CDATA[private $type$ _$property$;
public $type$ $property$
{
get { return _$property$;}
set
{
if (value != _$property$)
{
_$property$ = value;
OnPropertyChanged("$property$");
}
}
}
$end$]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
答案 2 :(得分:1)
绝对可以。
我建议先写一个实现INotifyPropertyChanged
的基类,给它一个protected void OnPropertyChanged(string propertyName)
方法,使其缓存其PropertyChangeEventArgs
个对象(每个唯一的属性名称一个 - 没有点在每次引发事件时创建一个新对象),并让你的T4生成的类派生自这个基础。
要获得需要实现属性的成员,您可以执行以下操作:
BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
FieldInfo[] fieldsNeedingProperties = inputType.GetFields(flags)
.Where(f => f.Name.StartsWith("p_"))
.ToArray();
从那里开始:
<# foreach (var field in fieldsNeedingProperties) { #>
<# string propertyName = GetPropertyName(field.Name); #>
public <#= field.FieldType.FullName #> <#= propertyName #> {
get { return <#= field.Name #>; }
set {
<#= field.Name #> = value;
OnPropertyChanged("<#= propertyName #>");
}
}
<# } #>
<#+
private string GetPropertyName(string fieldName) {
return fieldName.Substring(2, fieldName.Length - 2);
}
#>
等等。