2010-06-03 101 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