Xml namespaces for custom control libraries

Ok, it has been a while since I posted now, but there has been a too much going on, and I guess I should be blogging about Silverlight 5, as it is on the agenda for MIX. I have even had the possibility to early access to the Silverlight 5 bits, but I have had too much to do to come up with some good posts about it. That is not to say that there isn’t a huge amount of really good stuff in the next release! But besides not having had time to play with it, I am not allowed to blog about it until it is actually available…

But, in the mean time, I thought I would do a quick post about a little feature that I am not seeing a lot of people using. It is nothing ground breaking, or even very necessary, but still helpful. I am talking about the ability to declare custom Xml namspaces to your assemblies…

So what does it mean to declare a custom Xml namespace to your assemblies? Well, normally when you reference a CLR namespace in XAML, you write something like this

xmlns:myNamespace=”clr-namespace:MyNamespace.SubNamespace;assembly=MyAssembly

But, a lot of the Microsoft built stuff, such as the Silverlight toolkit for example, is referenced using an URI based  namespace instead of a CLR namespace like this

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

The cool thing is that this isn’t a custom thing that only Microsoft can do. It is actually something that you can do for your own control libraries.

If you open up the AssemblyInfo.cs file in the Properties directory in your project, you will see a bunch of assembly wide attributes. Assembly wide attributes doesn’t necessarily have to be declared in that file, but it is a good convention to have them all in one place. So that’s where I place mine…

Declaring a custom namespace to use as a reference to a CLR namespace, is done by adding assembly attribute, a System.Windows.Markup.XmlnsDefinitionAttribute. The constructor takes 2 string parameters. The first defines the Xml namespace you want to use, and the second the CLR namespace it corresponds to.

[assembly:XmlnsDefinitionAttribute("https://chris.59north.com/Controls","MyNamespace.SubNamespace")]

The above attribute makes it possible to use any control inside MyNamespace.SubNamespace in Xaml by adding the following Xml namespace declaration

xmlns:ctrl="https://chris.59north.com/Controls"

Ok…so that is kind of funky…but is it useful? Well, I think it is. It cleans up the code nicely, and can offer some other cool benefits. But let’s focus on the clean code…

You often declare controls in several different CLR namespaces, possibly throughout several different assemblies. This isn’t a problem as the XmlnsDefinitionAttribute can be added multiple times to an assembly. You can even declare several of them in the same assembly with the same Xml namespace, grouping several CLR namespaces under a single Xml namespace, cleaning up the code even further. Like this

[assembly:XmlnsDefinitionAttribute("https://chris.59north.com/Controls","MyNamespace.SubNamespace")]
[assembly:XmlnsDefinitionAttribute("https://chris.59north.com/Controls","MyNamespace.AnotherNamespace")]

The above attributes will allow you to use any control declared inside any of the two CLR namespaces by just defining a single Xml namespace.

You can even declare the same Xml namespace in several assemblies. And as long as those assemblies are referenced by your project, you will be able to use any control inside any of the defined CLR namespaces using only a single Xml namespace declaration. Cool right?

You can even add your own namespaces to any of the predefined Xml namespaces. I’m not sure that it is a great idea, but if you add the following attribute to your assembly

[assembly: XmlnsDefinitionAttribute("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "MyNamespace.SubNamespace")]

you don’t even need to use an Xml prefix to use your controls as the defined Xml namespace is the default namespace in Xaml. Funky, but also a little dangerous… :)

But there is one other feature, that the Microsoft assemblies use, that I really like. When you drag a control onto the design surface in Blend, it will automatically add the correct Xml namespace if it is missing. The annoying thing is that when it does it with any custom controls, it auto generates a namespace prefix based on the CLR namespace. This causes the namespace prefixes to become ridiculously long. Using the sample above, it would create something like this

xmlns:MyNamepsace_SubNamespace=”clr-namespace:MyNamespace.SubNamespace;assembly=MyAssembly”

This auto generation seems a little temperamental and depends on what tool you are using and so on… But generally it isn’t that great.

Luckily enough, this can also be changed using an attribute. in this case it is the System.Windows.Markup.XmlnsPrefixAttribute. It takes 2 string parameters, the Xml namespace to prefix, and the prefix to use. Like this

[assembly: XmlnsDefinitionAttribute("https://chris.59north.com/Controls", "Controls")]
[assembly: XmlnsPrefixAttribute("https://chris.59north.com/Controls", "MyControls")]

The above attributes means that when I drag a control from the Controls namespace onto the design surface, it created an Xml namespace declaration like this

xmlns:MyControls="https://chris.59north.com/Controls"

which makes the Xaml a lot tidier. In this case, I guess it doesn’t help that much as the CLR namespace was really simple, but with a longer namespace it helps…

A little gotcha!!! While playing around with this, it seems to have some issues with using the XmlnsDefinitionAttribute inside the application project. At least it seems to cause issues if you try to use the attributes inside a single application project. I guess it makes sense as I assume these attributes get read in during assembly loading, which would cause some issues with the Xaml parser when using it for the current assembly. But to be honest, I am just guessing. On the other hand, you normally use this for re-usable control libraries, in which case it works fine.

Ok, that was it for to day! A useful nugget of functionality that a friend of mine put me on to, and that I think more people could use…

Comments (1) -

What about adding XML namespaces for a windows form application? For instance, I want to define a custom textbox that inherits the windows textbox, but has some additional properties.

I am trying to dynamically generate a windows form based on an xml file, which will contain one of my custom controls. Currently, I am having difficulty figuring out how to do that so the custom defined controls are dynamically generated from the parsed xml.

Any thoughts?

Comments are closed