2010-06-03 70 views
10

我目前正在设置我的一个新项目,并想知道如何实现我的ViewModel类具有INotifyPropertyChanged支持,同时不需要自己手动编码所有属性。通过T4代码生成实现自动INotifyPropertyChanged实现?

我看着AOP框架,但我认为他们会炸毁我的项目与另一个依赖项。

所以我想到用T4生成属性实现。

设置将是这样的:我有一个ViewModel类,声明它的属性背景变量,然后使用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上发布我的想法,作为一个问题来获得一些反馈意见,也许有人建议如何做到更好/更容易/更安全。

+2

我觉得自己像一个白痴,但我不知道T4是什么,直到我只是因为这个问题而使用它。我不敢相信这不是更多的讨论! – BFree 2010-06-03 18:27:00

+0

我也是。我从一年前的C#预处理器线程(http://stackoverflow.com/questions/986404/does-a-c-preprocessing-tool-exist)得到了这里。卫生署。 – lo5 2010-06-04 09:30:17

+0

另请参阅http://stackoverflow.com/questions/1315621/implementing-inotifypropertychanged-does-a-better-way-exist – 2011-06-01 11:38:51

回答

7

Here's a great post by Colin Eberhardt通过使用EnvDTE直接从Visual Studio中检查自定义属性,从T4生成依赖属性。由于该文章包含浏览代码节点的简单实用方法,因此适应它来检查字段并适当地生成代码应该不难。

请注意,当从VS使用T4时,您不应该在自己的程序集上使用Reflection,否则它们会被锁定,您将不得不重新启动Visual Studio才能重建。

+0

这很甜蜜。我调整了模板以生成自定义类型描述符来做同样的事情。字面上保存了数千行代码。 – Will 2010-07-23 18:00:06

+1

请注意,从VS2010 SP1开始,锁定问题已解决,因此反射现在可以使用。 – GarethJ 2011-01-03 19:53:33

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); 
    } 
#> 

等。

+0

好的反射不是一个真正的选择(参见Julien Lebosquain的答案)。 – chrischu 2010-06-03 20:42:59

+1

@chrischu:如果你这么说。在我看来,彻底排除反思对于每个班只需要做一次的事情来说有点激烈。我以前多次使用这种技术为我编写课程,因为我不喜欢这么多打字。所以你必须在之后重新启动Visual Studio。那太可怕了吗? – 2010-06-04 12:16:11

+1

请注意,自VS2010 SP1起,解决了锁定问题。 – GarethJ 2011-01-03 19:53:17

3

有很多方法来剥皮这只猫。

我们一直在用PostSharp来注入INotifyProperty样板。这似乎很好。

这就是说,T4没有理由不工作。

我同意丹你应该创建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> 
+0

是的,我已经考虑使用代码片段。然而,使用代码片段仍然是更多的工作,然后使用T4(当它终于工作..) 我看着PostSharp,但事情是,我只是不想在我的项目中有更多的依赖项。 – chrischu 2010-06-03 20:44:45

+0

这是真的。但是,在我看来,我们在这种模式上花费了很多精力,只是因为我们讨厌它而且很丑。但它不难理解或维护。需要5秒钟才能添加属性和OnPropertyChanged样板。那么,有什么更好的2-3行重复代码或对PostSharp或一些钝的T4的依赖? – 2010-06-03 21:32:57

+0

每行2至3行重复代码。这加起来。此外,使用OnPropertyChanged生成的代码 - 调用OnPropertyChanged(“SomeProperty”)对拼写错误不安全的问题会自动克服,而不会影响运行时性能(如通过反射)。 – chrischu 2010-06-15 17:07:09