Colin Eberhardt's Adventures in WPF

Declarative Dependency Property Definition with T4 + DTE

August 18th, 2009

This blog post describes a technique for specifying WPF / Silverlight Dependency Properties declaritively via attributes as illustrated by the following example:

[DependencyPropertyDecl("Maximum", typeof(double), 0.0)]
[DependencyPropertyDecl("Minimum", typeof(double), 0.0)]
public partial class RangeControl : UserControl
{
    ...
}

At design-time the declarations are read via a T4 template and the required code is generated. For more information, read on …

A few months ago I wrote an article on codeproject about a technique for generating dependency properties via T4 templates. In brief; with this technique, you provide an XML description of your classes and their dependency properties, run the T4 template, and partial classes are generated which contain these properties – no more writing DP boiler plate code! For those of you who are unfamiliar with T4, it is a code generation engine which is built into Visual Studio, for a primer, I refer you to my codeproject article.

A few days back Daniel Vaughan published a blog post about using T4 templates to generate project meta-data. He demonstrated how this could be used to solve the age-old problem of hard-coded property name strings when implementing INotifyPropertyChanged. His solution uses both T4 and DTE – an automation library which allows you to programmatically access the items within your projects and solutions. Daniel’s blog post inspired me to revisit my DP code generation solution in order to simplify it and remove the need for the XML file.

My first step was to define a custom attribute which can be used to indicate that a class requires the template to generate a DP:

[AttributeUsage(AttributeTargets.Class , AllowMultiple = true)]
public class DependencyPropertyDecl : Attribute
{
    public DependencyPropertyDecl(string name, Type type, object defaultValue)
    {
        this.name = name;
        this.type = type;
        this.defaultValue = defaultValue;
    }
 
    public string name;
    public Type type;
    public object defaultValue;
}

With DTE it should be possible to inspect all the classes in the project, identifying those for which this attribute exists and generate the required DPs. However, looking at the DTE APIs this is not such an easy task, whilst the API defines a ‘base’ interface CodeElement from which CodeClass, CodeNamespace etc… derive, there is no unified concept of ‘Children’, also the Project and Solution are not CodeElements. In other words, in order to find all the classes in a solution you must recurse over a heterogeneous collection of classes and properties.

In order to ease the task of locating the classes within the project that have the DependencyPropertyDecl attribute associated, I created a simple Linq-to-DTE implementation:

public IEnumerable<CodeElement> CodeElementsInProjectItems(ProjectItems projectItems)
{
    foreach (ProjectItem projectItem in projectItems)
    {
        foreach(CodeElement el in CodeElementsInProjectItem(projectItem))
        {
            yield return el;
        }
    }
}
 
public IEnumerable<CodeElement> CodeElementsInProjectItem(ProjectItem projectItem)
{
    FileCodeModel fileCodeModel = projectItem.FileCodeModel;
 
    if (fileCodeModel != null)
    {
        foreach (CodeElement codeElement in fileCodeModel.CodeElements)
        {
            //WalkElements(codeElement, null);
            foreach(CodeElement el in CodeElementDescendantsAndSelf(codeElement))
            {
                yield return el;
            }
        }
    }
 
    if (projectItem.ProjectItems != null)
    {
        foreach (ProjectItem childItem in projectItem.ProjectItems)
        {
            foreach (CodeElement el in CodeElementsInProjectItem(childItem))
            {
                yield return el;
            }
        }
    }        
}
 
 
public IEnumerable<CodeElement> CodeElementsDescendants(CodeElements codeElements)
{
    foreach(CodeElement element in codeElements)
    {
        foreach (CodeElement descendant in CodeElementDescendantsAndSelf(element))
        {
            yield return descendant;                
        }
    }
}
 
public IEnumerable<CodeElement> CodeElementDescendantsAndSelf(CodeElement codeElement)
{
    yield return codeElement;
 
    CodeElements codeElements;
 
    switch(codeElement.Kind)
    {        
 
        /* namespaces */
        case vsCMElement.vsCMElementNamespace:
        {
            CodeNamespace codeNamespace = (CodeNamespace)codeElement;                                        
            codeElements = codeNamespace.Members;
            foreach(CodeElement descendant in CodeElementsDescendants(codeElements))
            {
                yield return descendant;                
            }
            break;
        }
 
        /* Process classes */
        case vsCMElement.vsCMElementClass:
        {            
            CodeClass codeClass = (CodeClass)codeElement;            
            codeElements = codeClass.Members;
            foreach(CodeElement descendant in CodeElementsDescendants(codeElements))
            {                
                yield return descendant;                
            }            
            break;    
        }        
    }    
}

There might be simpler way of achieving this, it is the first time I have created a recursive IEnumerable implementation, so please let me know if I have done something stupid! For a much more elegant solution to the problem of creating an IEnumerable implementation on a tree like structure via recursion have a look at this blog post by David Jade. However, as I mentioned earlier, the heterogeneous nature of the DTE API onto the project structure prohibits this method.

Anyhow, with this nasty IEnumerable implementation out of the way, we can use the power of Linq to provide a concise implementation of ‘Find all the classes in the solution which have one or more DependencyPropertyDecl attributes’, and perform the required code-gen as follows:

// for details of how the DTE 'project' is located see Daniel's blog post or the attached source of this blog.
var elements = CodeElementsInProjectItems(project.ProjectItems);
var classes = elements.Where(el => el.Kind == vsCMElement.vsCMElementClass)
                               .Cast<CodeClass>()
                               .Where(cl => Attributes(cl).Any(at => at.Name=="DependencyPropertyDecl"));
 
foreach(var clazz in classes)
{
    GenerateClass(clazz);
}

The GenerateClass function is a simple modification of the one I wrote for generating classes based on XML descriptions. In this implementation we acquire the CodeAttribute.Value property for each of our custom attribute instances and from there obtain the DP name, type and default value:

<#+
/// 
/// Generates a class along with its associated DPs
/// 
private void GenerateClass(CodeClass clazz)
{
    string classNamespace = clazz.Namespace.Name;
    string className =  clazz.Name;

    bool classRaisesPropertyChanged = false;

#>

namespace <#= classNamespace #>
{
    public partial class <#= className #> <#+ if(classRaisesPropertyChanged){ #>: INotifyPropertyChanged<#+ } #>
    {
<#+
    var attributes = Attributes(clazz).Where(att => att.Name=="DependencyPropertyDecl");
    foreach(CodeAttribute attribute in attributes)
    {
        string[] attributeValues = attribute.Value.Split(',');

        string propertyName = attributeValues[0].Trim().Replace("\"","");
        string propertyType = attributeValues[1].Trim().Substring(7, attributeValues[1].Length - 9);
        string summary = null;
        string metadata = null;
        string defaultValue = attributeValues[2].Trim();
        string typeConverter = null;
        bool propertyChangedCallback = true;
        bool isAttached = false;
        #>

        #region <#= propertyName #>
        <#+        

        GenerateCLRAccessor(typeConverter, propertyType, propertyName, summary);

        bool handleDPPropertyChanged = propertyChangedCallback || classRaisesPropertyChanged;

        GenerateDependencyProperty(className, propertyType, defaultValue, propertyName,
                                   handleDPPropertyChanged, isAttached, metadata, summary);        

        if (handleDPPropertyChanged)
        {
            GenerateChangeEventHandler(className, propertyName, propertyChangedCallback, classRaisesPropertyChanged);
        } 

        if (isAttached)
        {
            GenerateAttachedPropertyAccessor(propertyName, propertyType);
        }
        #>
        #endregion
    <#+
    } // end foreach dps

    if (classRaisesPropertyChanged)
    {
        GenerateINotifyPropertChangedImpl();
    }
    #>
    }
}

<#+
}
#>

(please forgive the lack of syntax highlighting wordpress/codeproject do not support T4 templates!)

The GenerateCLRAccessor, GenerateDependencyProperty, … functions are re-used from my previous XML-based approach to DP generation.

For a simple demonstration of this approach, here is the complete implementation for a simple range control which has a Maximum and Minimum property, where if the user enters a Minimum which is greater that the Maximum, the values are swapped:

<UserControl x:Class="WpfDeclarativeDPCodeGen.RangeControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    DataContext="{Binding RelativeSource={RelativeSource Self}}">
    <StackPanel x:Name="LayoutRoot" Background="White" Orientation="Horizontal">
        <TextBox  Width="50" Text="{Binding Minimum}"/>
        <TextBlock Text=" : " VerticalAlignment="Center"/>
        <TextBox  Width="50" Text="{Binding Maximum}"/>
    </StackPanel>
</UserControl>
[DependencyPropertyDecl("Maximum", typeof(double), 0.0)]
[DependencyPropertyDecl("Minimum", typeof(double), 0.0)]
[TypeConverter(typeof(string))]
public partial class RangeControl : UserControl
{
    public RangeControl()
    {
        InitializeComponent();
    }
 
    /// <summary>
    /// If max is less than min, swap their values
    /// </summary>
    private void Swap()
    {
        if (Maximum < Minimum)
        {
            double swap = Minimum;
            Minimum = Maximum;
            Maximum = swap;
        }
    }
 
    partial void OnMaximumPropertyChanged(DependencyPropertyChangedEventArgs e)
    {
        Swap();
    }
 
    partial void OnMinimumPropertyChanged(DependencyPropertyChangedEventArgs e)
    {
        Swap();
    }
}

When using this approach the workflow is quite simple, create your class, add the DependencyPropertyDecl attributes, then execute the code generation template. The output is an accompanying partial class which contains the DP code itself, plus partial methods which can be implemented in order to perform logic when the property changes.

I have not-yet completely ported my XML-based DP generation templates to this new declarative approach, for example the DependencyPropertyDecl attribute needs to also indicate property meta-data, whether a property is attached etc … However, I thought I would share my ideas in case I didn’t get the time (or urge) to make a complete implementation.

I feel that this approach has great potential far beyond DP code generation, simple examples could include attributes that indicate that a T4 template should generate a ‘generic’ INotifyPropertyChanged or IEditableObject implementation, and of course, the more complex application-specific possibilities are endless.

You can download an example project containing the RangeControl above: WpfDeclarativeDpCodeGen.zip

Try adding new DependencyPropertyDecl attributes, and re-run the code generation template (right click CodeGen/GeneratedObjects.tt -> Run Custom Tool), and inspect the generated output – CodeGen/GeneratedObjects.cs.

Finally, thanks to Daniel Vaughan for the inspiration.

Regards,
Colin E.

Dependency Property Performance and Lissajous Figures

June 2nd, 2009

A few night ago I was working on a Siverlight control which renders some quite complex Paths, the geometry of which is determined from a number of dependency properties. In order to gain UI coolness points I wanted to animate the dependency properties in order to see a smooth transition of the Path geometry between the old and new values. The animation itself was easy to implement, but the resultant animation was distinctly choppy.

Now, I cannot share the code of the Silverlight control I was working on, so I have decided to illustrate the point via a Lissajous Figure. These curves are plotted using the following simple formula:

A simple Lissajous Figure can be constructed by creating a UserControl which dependency properties for the various parameters in the above equations. The control contains a single path whose Data property will be set to a suitable geometry in code behind, and a ‘container’ element for our path which we use to determine the width / height of our curve.

<UserControl ...>
    <Grid x:Name="LayoutRoot" Background="White">
        <Grid x:Name="PathContainer" Margin="5">            
            <Path x:Name="lissajousFigure" Stroke="#9EFFFF" StrokeThickness="1"/>
        </Grid>
    </Grid>
</UserControl>

The points that are used to construct the geometry are calculated from the ActualXFrequency, ActualYFrequency, ActualPhase properties of our user control, together with the ActualWidth and ActualHeight of the container in order to scale the curve appropriately.

for(double t = 0; t < Math.PI * 10; t += Math.PI / 36)
{
    points.Add(new Point()
    {
        X = PathContainer.ActualWidth * Math.Sin(t * ActualXFrequency) / 2
            + ActualWidth / 2,
        Y = PathContainer.ActualHeight * Math.Cos(t * ActualYFrequency + ActualPhase) / 2
            + PathContainer.ActualHeight / 2
    });
}

When I investigating the choppy animation performance in my Silverlight control I concentrated initially on other parts of the application; the construction of the paths, the property changed events and the resultant chain reaction of event which can result in a spiders-web of method invocations. It was not until a little later that I focussed on the code that constructed the geometry, which looks not too dissimilar to the above.

At first sight, the code looks just fine, we are performing a number of simple operations on a few simple properties. However, this is not the case, these properties are not simple CLR properties backed by value or reference types. These are Dependency Properties, which are much more complex beasts!

A quick change to the above code to ensure that the DP accessors are called only once, rather than 360 times, resulted in code which ran ~400 times faster!

double actualWidth = PathContainer.ActualWidth;
double actualHeight = PathContainer.ActualHeight;
double actualXFrequency = ActualXFrequency;
double actualPhase = ActualPhase;
double actualYFrequency = ActualYFrequency;
 
for(double t = 0; t < Math.PI * 10; t += Math.PI / 36)
{
    points.Add(new Point()
    {
        X = actualWidth * Math.Sin(t * actualXFrequency) / 2
            + actualWidth / 2,
        Y = actualHeight * Math.Cos(t * actualYFrequency + actualPhase) / 2
            + actualHeight / 2
    });
}

When you think about the features that the DP framework provides (databinding, animation, inheritance etc …), it is not at all surprising that this is at some performance cost. And I will forgive the reader if they tell me that I am stating the obvious! However, in code behind, where DPs are accessed via their CLR wrappers it is easy to forget this. It should also be noted that DPs are far from slow. It is only when they are used as part of a complex iterative calculations that the performance-hit will be felt.

Anyhow, this is a small lesson in what is possibly obvious! However, I must admit, I had far too much fun creating the Lissajous Figure example application as you can see from the app. at the start of this article … it takes me back to Physics lab at University!

A few other points of interest:

  • The code uses ElementName binding attached behaviour I created in an earlier blog post. As a result, there is no code-behind in the main page (I may be flirting with Silverlight but my WPF credibility remains intact!)
  • The various dependency properties for the Lissajous Figure user control are defined using T4 templates as described in this codeproject article.

I also really like the way that when one of the DPs such as Phase is updated, a storyboard is used to animate the accompanying ActualPhase DP to the updated value.

partial void OnPhasePropertyChanged(DependencyPropertyChangedEventArgs e)
{
    AnimateProperty("ActualPhase", Phase, 100);
}
 
private void AnimateProperty(string propertyName, double targetValue, int milliseconds)
{
    Storyboard sb = new Storyboard();
 
    DoubleAnimation b = new DoubleAnimation() { To = targetValue };
    b.Duration = new Duration(new TimeSpan(0, 0, 0, 0, milliseconds));
    sb.Children.Add(b);
    Storyboard.SetTarget(b, this);
    Storyboard.SetTargetProperty(b, new PropertyPath("(" + propertyName + ")"));
 
    sb.Begin();
}

This means that even though the slider controls bound to the DPs move in discrete steps, the above animation gives the illusion of the steps being continuous.

You can download the full project source here: silverlightdpperformance.zip.

[Oscilloscope image reproduced from Wikipedia under Creative Commons Licence]

Regards, Colin E.