All,
I have a T4 template that generates boiler-plate code that handles my property-changed notification and automatically registers dependancyproperties for me based on attributes I have assigned to the class. I accomplish this using EnvDTE to walk up and down the project and retrieve an IEnumerable of ClassInfo objects. I then enumerate through the ClassInfo.Attributes to retrieve ClassInfo objects that have certain custom attributes I created (i.e. INotifyPropertyChangedAttributeAttribute:System.Attribute) with all the relavent information I need to have the template write the boiler-plate code for me.
Now, my question is, is it possible to (using EnvDTE) check for an Interface implementation (such as INotifyPropertyChanged) which might be inheritied from a base class so that I don't end up with two PropertyChanged events in my class (one in the inherited class and one in the code-generated partial class)?
For examle:
public class vmBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged
protected override void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null) PropertyChanged(this, e);
}
}
[INotifyPropertyChangedAttribute(Test1, typeof(string))] //NOTE: By including this attribute, T4 template will automatically generate properties. What I need to know, though, is if the EnvDTE.ClassInfo can show Internface implementations as well so that I don't recreate the INotifyPropertyChanged Event
public partial class vm: vmBase //Implements INotifyPropertyChanged
{
//....
}
[INotifyPropertyChangedAttribute(Test2, typeof(string))]
public partial class SomeClassThatDoesNotImplementInotifyPropertyChangedAlready
{
//....
}
Hopefully that makes some sense.
See http://www.scottlogic.co.uk/blog/colin/2009/08/declarative-dependency-property-definition-with-t4-dte/ for an example of using envDTE and T4 to take care of dependancyproperty registrations. Concepts in my project are the same, only I'm adapting it to handle INotifyPropertyChanged boiler-plate code.
Thanks in advance.
It took me a little, but yes - there is a way to find out via EnvDTE if a given class somehow inherits a given interface.
This code fragment only detects classes that inherit directly from another class that implements INotifyPropertyChanged. So before using it, one would add some recursive logic here...
<#
// get a reference to the project of this t4 template
var project = VisualStudioHelper.CurrentProject;
// get all class items from the code model
var allClasses = VisualStudioHelper.GetAllCodeElementsOfType(project.CodeModel.CodeElements, EnvDTE.vsCMElement.vsCMElementClass, false);
// iterate all classes
foreach(EnvDTE.CodeClass codeClass in allClasses)
{
// get all interfaces implemented by this class
var allInterfaces = VisualStudioHelper.GetAllCodeElementsOfType(codeClass.ImplementedInterfaces, EnvDTE.vsCMElement.vsCMElementInterface, true);
if (allInterfaces.OfType<EnvDTE.CodeInterface>()
.Any(i => i.Name == "INotifyPropertyChanged"))
{
#>Implements Interface Directly: <#= codeClass.FullName #>
<#
// find classes that derive from this code class
foreach(EnvDTE.CodeClass potentialDerivingClass in allClasses)
{
IEnumerable<string> theBases = VisualStudioHelper.GetAllCodeElementsOfType(potentialDerivingClass.Bases, EnvDTE.vsCMElement.vsCMElementClass, true).OfType<EnvDTE.CodeClass>().Select(cc => cc.FullName);
if (theBases.Any(b => b == codeClass.FullName))
{
#>Derives from implementing class: <#= potentialDerivingClass.FullName #>
<#
}
}
}
}
#>
So given a class A that implements INotifyProperty changed, a class B deriving from A and another class C deriving from B, this code would come up with classes A and B that implement INotifyPropertyChanged.
Note: Because using the EnvDTE classes is not that nice, I used a reusable template from tangible T4 Editor's free template gallery named "tangible Visual Studio Automation Helper" - that makes it much easier to use!