How To: Generate Code from Team System UML Diagrams in VS 2010 Team System Beta 2 (Update 4)


UPDATE: You can find an updated description for VS 2010 RTM here

Here is the first code-snippet about how to generate code from UML-Diagrams using T4 Text-Templates. 

image

Here are the steps:

1. Create a model project called ModelingProject1.modelproj

2. Insert Classes with properies at the root level of the model using the diagrams

3. Create a file Generator.tt that contains the text below

4. Save the .tt file to have a code-behind template generated under the .tt file that contains the output.

5. If you want to regenerate press the new button (most right in the toolbar of the solution explorer called “Transform All Templates” or save the template again

6. Optional: To get Syntax Coloring and intelli-sense on the template go to the Extension Manager (Tools Menu->Extension Manager->Online Gallery) and search for a T4 Editor of your choice.

Here is the code for copy paste:

<#@ template language="C#" debug="true" hostSpecific="true" #>
<#@ output extension=".cs"#>
<#@ assembly name="Microsoft.VisualStudio.Uml.Extensions.dll"#>
<#@ assembly name="Microsoft.VisualStudio.Uml.Interfaces.dll"#>
<#@ assembly name="Microsoft.VisualStudio.Uml.Interfaces.dll"#>
<#@ import namespace="Microsoft.VisualStudio.Uml.Classes" #>
<#@ import namespace="Microsoft.VisualStudio.Uml.Extensions" #>
<#   

string projectPath = System.IO.Path.GetDirectoryName(this.Host.TemplateFile)
                    + @"\..\ModelingProject1\ModelingProject1.modelproj";
using (IModelingProject project = ModelingProject.Load(projectPath))
{
   IModelStore store = project.Store;
   foreach (IElement element in store.Root.OwnedElements)
   {
      IClass classElement = element as IClass;
      if (classElement != null) {
        #>

        class <#= classElement.Name #> {
           <# foreach (IFeature theFeat in classElement.Features){#>
              string <#= theFeat.Name #> {get;set;};
           <#}#>
        }
        <#
      }
   }
   project.Close();
}
#>

Note there are also a lot of extenison methods defined for IUML*. Here is a list of tasks you can do with the UML API easier. I did not try it though.

http://msdn.microsoft.com/en-us/library/ee329525(VS.100).aspx

And here is a more complex sample that generates class and properties from the Model.

<#@ template language="C#3.5" debug="true" hostSpecific="true" #>
<#@ Assembly Name="System.Core.dll" #>
<#@ assembly name="Microsoft.VisualStudio.Uml.Extensions.dll"#>
<#@ assembly name="Microsoft.VisualStudio.Uml.Interfaces.dll"#>
<#@ import namespace="System" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="Microsoft.VisualStudio.Uml.Classes" #>
<#@ import namespace="Microsoft.VisualStudio.Uml.Extensions" #>
using System;
<#   
var projectPath = System.IO.Path.GetDirectoryName(this.Host.TemplateFile)+ @"\..\ModelingProject1\ModelingProject1.modelproj";
using (IModelingProject project = ModelingProject.Load(projectPath))
{
   foreach(IClass classElement in project.Store.Root.OwnedElements.OfType<IClass>())
   {
    var baseClass = classElement.SuperClasses.FirstOrDefault();
    var baseClassNamespaceName = (baseClass!=null ) ? baseClass.Namespace.Name+"." : "";
    var baseClassName = (baseClass!=null) ? baseClassNamespaceName+baseClass.Name : "System.Object";
    var properties = classElement.OwnedAttributes.OfType<IProperty>().ToArray();

    #>
public <#= classElement.IsAbstract ? "abstract ":"" #>partial class <#= classElement.Name #>: <#= baseClassName #>
{
<#
    if (properties.Length>0)
    {
     WriteLine("\t\t// properties");
    }
    foreach(IProperty property in properties)
    {
     var propertyName = property.Name;
     var fieldName = "_"+property.Name.Substring(0,1).ToLowerInvariant()+property.Name.Substring(1);
     var propertyTypeName = typeof(System.Object).FullName;
     if (property.Type!=null)
     {
      propertyTypeName = property.Type.Name;
      if (property.Type.Namespace!=null && property.Type.Namespace.Name!=baseClassNamespaceName)
      {
       propertyTypeName = property.Type.Namespace.Name+"."+propertyTypeName;
      }
     }
     //var propertyTypeName = (property.Type!=null) ? property.Type.Name : ;
#>
  #region @ <#= propertyName #>
  private <#= propertyTypeName #> <#= fieldName #>;
  public <#= propertyTypeName #> <#= propertyName #>
  {
   get
   {
    return <#= fieldName #>;
   }
   set
   {
   }
  }
  #endregion
<#
    }
    #>
}

<#
  }
project.Close();
}

#>

Comments (5)

  1. Hal says:

    Is it feasible to load a ModelingProject from a class library?  I tried and had difficult resolving Microsoft.Build.  Haven’t found a good tt editing extension for VS2010 that has code completion support.  

  2. Tim Fischer says:

    I did not try it but here is a how to on this.

    http://msdn.microsoft.com/en-us/library/ee329477(VS.100).aspx

    I assume you need to make sure  that the DSL that defines the UML Model is referenced to not get a SerialisationHelper Missing exception.

  3. Ron Krauter says:

    Could you please make your screen captures bigger in the future. Too hard to see

  4. timfis says:

    Screenshot now with better quality please klick one on it

  5. Lothar Grieb says:

    Hi Tim, very usefull your examples. I played a little bit around and expanded the tt sript:

    <#@ template language="C#3.5" debug="true" hostSpecific="true" #>

    <#@ Assembly Name="System.Core.dll" #>

    <#@ assembly name="Microsoft.VisualStudio.Uml.Extensions.dll"#>

    <#@ assembly name="Microsoft.VisualStudio.Uml.Interfaces.dll"#>

    <#@ import namespace="System" #>

    <#@ import namespace="System.Linq" #>

    <#@ import namespace="System.Collections.Generic" #>

    <#@ import namespace="Microsoft.VisualStudio.Uml.Activities" #>

    <#@ import namespace="Microsoft.VisualStudio.Uml.Classes" #>

    <#@ import namespace="Microsoft.VisualStudio.Uml.Interactions" #>

    <#@ import namespace="Microsoft.VisualStudio.Uml.Components" #>

    <#@ import namespace="Microsoft.VisualStudio.Uml.Extensions" #>

    <#    

    new ModelWriter(this)

    {

    ProjectFullFileName = System.IO.Path.GetDirectoryName(this.Host.TemplateFile)+ @"..ModelingProject1ModelingProject1.modelproj",

    PropertyMode = PropertyMode.Bindable, // AutoImplemented, BackingField or Bindable

    UsePartialClasses = true,

    GenerateINotifyPropertyChangedEvent = true,

    UseRegions = true,

    }.Write();

    #>

    <#+

    }

    public enum PropertyMode

    {

    AutoImplemented, BackingField, Bindable

    }

    public class ModelWriter

    {

    protected Microsoft.VisualStudio.TextTemplating.TextTransformation TT { get; private set; }

    public String ProjectFullFileName { get; set; }

    public PropertyMode PropertyMode  { get; set; }

    public Boolean UseRegions { get; set; }

    public Boolean UsePartialClasses  { get; set; }

    public Boolean GenerateINotifyPropertyChangedEvent  { get; set; }

    private Int16 Tabs = 0;

    public ModelWriter(Microsoft.VisualStudio.TextTemplating.TextTransformation tt)

    {

    TT = tt;

    PropertyMode = PropertyMode.AutoImplemented;

    UseRegions = true;

    UsePartialClasses = true;

    GenerateINotifyPropertyChangedEvent = false;

    }

    public void Write()

    {

    using (IModelingProject project = ModelingProject.Load(ProjectFullFileName))

    {

    var root = project.Store.Root;

    List<IPackage> packages = root.OwnedElements.OfType<IPackage>().ToList();

    List<IClass> classes = root.OwnedElements.OfType<IClass>().ToList();

    List<IComponent> components = root.OwnedElements.OfType<IComponent>().ToList();

    List<IActivity> activities = root.OwnedElements.OfType<IActivity>().ToList();

    List<IInteraction> interactions = root.OwnedElements.OfType<IInteraction>().ToList();

    foreach(IPackage package in packages)

    {

    var namespaceName = package.Name;

    TT.WriteLine(Tabs, "namespace {0}", namespaceName);

    TT.WriteLine(Tabs++, "{");

    package.OwnedElements.OfType<IClass>().ToList().ForEach(c=>WriteClass(c, namespaceName));

    TT.WriteLine(–Tabs, "}");

    TT.WriteLine();

    }

    }

    }

    private void WriteClass(IClass classElement, String namespaceName)

    {

    var baseClass = classElement.SuperClasses.FirstOrDefault();

    var baseClassNamespaceName = (baseClass!=null && baseClass.Namespace.Name!=namespaceName) ? baseClass.Namespace.Name+"." : "";

    var baseClassName = (baseClass!=null) ? baseClassNamespaceName+baseClass.Name : "System.Object";

    var properties = classElement.OwnedAttributes.OfType<IProperty>().ToArray();

    /*IStereotypeInstance st = classElement.AppliedStereotypes.FirstOrDefault();

    if (st!=null)

    {

    foreach(IStereotypePropertyInstance x in st.PropertyInstances)

    {

    TT.WriteLine(Tabs,"// "+x.Name+"="+x.Value);

    }

    }*/

    TT.WriteLine(Tabs, "public {0}{1}class {2}: {3}{4}",

    classElement.IsAbstract ? "abstract ":String.Empty,

    UsePartialClasses ? "partial ":String.Empty,

    classElement.Name,

    baseClassName,

    GenerateINotifyPropertyChangedEvent ? ", System.ComponentModel.INotifyPropertyChanged":String.Empty

    );

    TT.WriteLine(Tabs++, "{");

    TT.WriteLine(properties.Length>0, Tabs, "// properties");

    foreach(IProperty p in properties)

    {

    TT.WriteLine(UseRegions, Tabs, "#region @ {0}",p.PropertyName());

    TT.WriteLine();

    if (PropertyMode==PropertyMode.AutoImplemented)

    {

    TT.WriteLine(Tabs, "public {0} {1} {{get; set;}}", p.TypeName(), p.PropertyName());

    }

    else

    {

    TT.WriteLine(Tabs, "private {0} {1};", p.TypeName(), p.BackingFieldName());

    TT.WriteLine();

    TT.WriteLine(Tabs, "{0} {1} {2}", p.ModifierName(), p.TypeName(), p.BackingFieldName());

    TT.WriteLine(Tabs++, "{");

    TT.WriteLine(Tabs, "get");

    TT.WriteLine(Tabs++, "{");

    TT.WriteLine(Tabs, "return {0};", p.BackingFieldName());

    TT.WriteLine(–Tabs, "}");

    TT.WriteLine(Tabs, "set");

    TT.WriteLine(Tabs++, "{");

    if (PropertyMode==PropertyMode.BackingField)

    {

    TT.WriteLine(Tabs, "{0} = value;", p.BackingFieldName());

    }

    else

    {

    TT.WriteLine(Tabs, "if (value != {0})", p.BackingFieldName());

    TT.WriteLine(Tabs++, "{");

    TT.WriteLine(Tabs, "{0} = value;", p.BackingFieldName());

    TT.WriteLine(Tabs, "RaisePropertyChanged("{0}");", p.PropertyName());

    TT.WriteLine(–Tabs, "}");

    }

    TT.WriteLine(–Tabs, "}");

    TT.WriteLine(–Tabs, "}");

    }

    TT.WriteLine(UseRegions);

    TT.WriteLine(UseRegions, Tabs, "#endregion");

    }

    if (GenerateINotifyPropertyChangedEvent)

    {

    TT.WriteLine(properties.Length>0, Tabs, "// events");

    TT.WriteLine(UseRegions, Tabs, "#region ! PropertyChanged" );

    TT.WriteLine(UseRegions);

    TT.WriteLine(Tabs, "public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;");

    TT.WriteLine();

    TT.WriteLine(UseRegions, Tabs, "#endregion" );

    TT.WriteLine(properties.Length>0, Tabs, "// methods");

    TT.WriteLine(UseRegions, Tabs, "#region RaisePropertyChanged" );

    TT.WriteLine(UseRegions);

            TT.WriteLine(Tabs, "protected void RaisePropertyChanged(String propertyName)");

            TT.WriteLine(Tabs++, "{");

    TT.WriteLine(Tabs, "var handler = PropertyChanged;");

    TT.WriteLine(Tabs, "if (handler!=null)");

    TT.WriteLine(Tabs++, "{");

    TT.WriteLine(Tabs, "handler(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));");

    TT.WriteLine(–Tabs, "}");

    TT.WriteLine(–Tabs, "}");

    TT.WriteLine();

    TT.WriteLine(UseRegions, Tabs, "#endregion" );

    }

    TT.WriteLine(–Tabs,"}");

    TT.WriteLine();

    }

    }

    public static class Extensions

    {

    public static void WriteLine(this Microsoft.VisualStudio.TextTemplating.TextTransformation source, Boolean condition, Int16 tabs, String textToAppend)

    {

    if (condition)

    {

    source.Write(new String(‘t’, tabs));

    source.WriteLine(textToAppend);

    }

    }

    public static void WriteLine(this Microsoft.VisualStudio.TextTemplating.TextTransformation source, Boolean condition, Int16 tabs, String format, params Object[] args)

    {

    if (condition)

    {

    source.Write(new String(‘t’, tabs));

    source.WriteLine(format, args);

    }

    }

    public static void WriteLine(this Microsoft.VisualStudio.TextTemplating.TextTransformation source, Boolean condition)

    {

    if (condition)

    {

    source.WriteLine(String.Empty);

    }

    }

    public static void WriteLine(this Microsoft.VisualStudio.TextTemplating.TextTransformation source, Int16 tabs, String textToAppend)

    {

    source.Write(new String(‘t’, tabs));

    source.WriteLine(textToAppend);

    }

    public static void WriteLine(this Microsoft.VisualStudio.TextTemplating.TextTransformation source, Int16 tabs, String format, params Object[] args)

    {

    source.Write(new String(‘t’, tabs));

    source.WriteLine(format, args);

    }

    public static void WriteLine(this Microsoft.VisualStudio.TextTemplating.TextTransformation source)

    {

    source.WriteLine(String.Empty);

    }

    public static String PropertyName(this IProperty source)

    {

    return source.Name;

    }

    public static String BackingFieldName(this IProperty source)

    {

    var name = source.PropertyName();

    return (name.Length<=2)

    ? ‘_’+name.ToLowerInvariant()

    : "_"+name.Substring(0,1).ToLowerInvariant()+name.Substring(1);

    }

    public static String TypeName(this IProperty source)

    {

    return source.TypeName(null);

    }

    public static String TypeName(this IProperty source, String defaultNamespaceName)

    {

    var name = typeof(System.Object).FullName;

    if (source.Type!=null)

    {

    name = source.Type.Name;

    if (source.Type.Namespace!=null && source.Type.Namespace.Name!=defaultNamespaceName)

    {

    name = source.Type.Namespace.Name+"."+name;

    }

    }

    return name;

    }

    public static String ModifierName(this IProperty source)

    {

    switch (source.Visibility)

    {

    case VisibilityKind.Public:

    return "public";

    case VisibilityKind.Protected:

    return "protected";

    case VisibilityKind.Private:

    return "private";

    default:

    return "internal";

    }

    }

    #>

Skip to main content