There are numerous good books and articles about WPF in general and some basic information on custom control development but I have yet to find a good article (or book) with in-depth coverage of custom control development in general and design-time related issues in particular.

I’ve done my share of custom ASP.NET control development (see ASP.NET Controls for amCharts http://www.amcharts.com/aspnet, or SPAW Editor ASP.NET Edition http://spaweditor.com), and actually the basic principles are not that different. However some things should be implemented in a totally different manner and it wasn’t really obvious to me where those differences start and what to do about them. I’ve spent quite some time figuring these things out, so I decided to share my findings here hoping that it would save someone some time which could be better spent implementing new features.

This article covers several areas related to WPF Designer related features/issues which are implemented using different means than you would use while building ASP.NET/WinForms controls.

Metadata Store and Separate Metadata Assembly

Some design-time related attributes like CategoryAttribute (which specifies grouping category in property grid) could be set on a property the “old-fashioned” way, but general approach has switched toward the Metadata Store. Metadata store is a mechanism used by WPF Designer to decouple design-time metadata from implementation.

Design-time metadata is deployed in separate specialized assemblies which should follow specific naming conventions in order for design tools to find and use them. You create an assembly with “.Design” appended to the main assembly name for general design-time metadata.

For example if you have an implementation assembly called MyLibrary.dll then design-time metadata should reside in MyLibrary.Design.dll. Specialized Visual Studio or Expression Blend metadata could be placed in additional MyLibrary.VisualStudio.Design.dll and MyLibrary.Expression.Design.dll.

In addition to general good design principles, separation of design-time metadata into specialized assemblies has one very practical implication, most of the new attribute classes are defined in the Microsoft.Windows.Design.dll. If you add a reference to this DLL to your implementation project users of your control will most likely get an exception like “Unable to install or run the application. The application requires that the assembly Microsoft.Windows.Design Version 3.5.0.0 be installed in the Global Assembly Cache (GAC) first. Since it’s not a part of normal .NET deployment runtime.

To create a metadata store, you create a new project, add a reference to Microsoft.Windows.Design.dll to it and create a class that implements IRegisterMetadata interface like this:

1:namespaceMyLibrary.Design

2: {

3:internalclassMyLibraryMetadata : IRegisterMetadata

4: {

5:publicvoid Register()

6: {

7:AttributeTableBuilder builder = newAttributeTableBuilder();

8:builder.AddCustomAttributes(typeof(MyClass)

9: ,newToolboxBrowsableAttribute(false));

10:MetadataStore.AddAttributeTable(builder.CreateTable());

11: }

12: }

13: }

The IRegisterMetadata interface requires you to implement only one method – Register(). In this method you create an instance of AttributeTableBuilder and add attributes to your classes, properties, methods, etc. one-by-one using AddCustomAttributes() method. Then you add this table to the MetadataStore.

Toolbox visibility

When you create a control library you will most likely create some classes deriving from Control class (or one of it’s derivatives), you don’t want then to show up in the Visual Studio toolbox along your main controls. In ASP.NET/WinForms you would use the ToolboxItem(false) attribute to achieve that. However the WPF designer pays no attention to this attribute. For the WPF designer you should use ToolboxBrowsableAttributefrom the Microsoft.Windows.Design namespace. You attach it to your classes like this:

1:builder.AddCustomAttributes(typeof(MyClass)

2: , newToolboxBrowsableAttribute(false));

Toolbox icon

You can add toolbox icon for your controls using ThumbnailAttribute class. However this attribute was only added in .NET 3.5 Service Pack 1. So, you have to make a choice here, supporting .NET 3.5 without SP1 and earlier versions of the .NET Framework, or specifying different thumbnails for Visual Studio and Expression Blend.

A simple and version agnostic method is to add images named according to the specific naming convention of your project. The convention is to name an image in a form of ClassName.Icon.ext. So, if you have a class named MyControl, then your icon should be named MyControl.Icon.png (for example).

Collection editors

In previous .NET designer technologies you had to create a class derived from System.ComponentModel.Design.CollectionEditor if you wanted to allow users to add objects of more than one type to collections through the collection editor in Visual Studio. The approach is demonstrated in this CodeProject article.

In WPF this no longer works.

But fortunately you can achieve the same result just by setting NewItemTypesAttribute on your property. This is how it’s done. Suppose you have a property defined as a collection of brushes like this:

1:List<Brush> MyBrushes;

And you want users to be able to add SolidColorBrush and LinearGradientBrush objects to this collection via collection editor in Visual Studio. You do this by attaching NewItemTypesAttribute attribute in Register method of your metadata class like this:

Conclusion

This article touched only some of the issues which developers new to WPF control development may encounter. As WPF gains more and more popularity eventually someone will write a good book and/or tutorial on the subject. Maybe someone already did and I just wasn’t lucky to find it. If so, please, let me know by commenting.

However there’s pretty detailed coverage of WPF designer extensibility in this MSDN library section even though it’s is not written in a very narrative tutorial-like style.

Alan.

As a bonus to this article Alan has included a 50% discount coupon for the WPF charting controls (http://wpf.amcharts.com) he has been working on lately. All you have to do is enter “dev102” (without quotes) when ordering it.

One Response to “4 Great Tips for Custom WPF Controls Developers”

matsolof

Said on
October 1, 2010 :

I’m a C# beginner. I’m trying to figure out how to use shortcuts in an xaml menu. This is one of the pages Google suggested. The perhaps 10 sets of example code I’ve tried sofar have only generated error messages. Any suggestions?