I\'m currently working on setting up a new project of mine and was wondering how I could achieve that my ViewModel classes do have INotifyPropertyChanged support while not h
Here's a great post by Colin Eberhardt on generating Dependency Properties from a T4 by inspecting custom attributes directly from Visual Studio with EnvDTE. It shouldn't be difficult to adapt it to inspect fields and generate code appropriately since the post contains simple utility methods to browse code nodes.
Note that when using T4 from VS, you shouldn't use Reflection on your own assemblies or they'll get locked and you'll have to restart Visual Studio in order to rebuild.
It should definitely work.
I'd recommend first writing a base class that implements INotifyPropertyChanged
, giving it a protected void OnPropertyChanged(string propertyName)
method, making it cache its PropertyChangeEventArgs
objects (one per unique property name -- no point in creating a new object every time the event is raised), and have your T4-generated class derive from this base.
To get the members that need properties implemented, you can just do something like:
BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
FieldInfo[] fieldsNeedingProperties = inputType.GetFields(flags)
.Where(f => f.Name.StartsWith("p_"))
.ToArray();
And go from there:
<# 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);
}
#>
And so on.
There are a lot of ways to skin this cat.
We have been toying with PostSharp to inject the INotifyProperty boilerplate. That seems to work pretty good.
That being said, there's no reason why T4 wouldn't work.
I agree with Dan that you should create the base class implementation of OnPropertyChanged.
Have you considered just using a code snippet? It will write the boilerplate for you. The only disadvantage is that it will not update automatically if you want to change the property name at some later date.
<?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>