Extending the WPF XML namespaces

Rob Relyea might not like this, but today I had an idea.

When referencing controls from another assembly in XAML, one can either use xmlns:foo="clr-namespace:MyNamespace;assembly=MyAssembly" syntax, or a URI mapped with the XmlnsDefinition attribute. MSDN can tell you all about the attribute. Currently in Magellan I use it like this:

[assembly: XmlnsDefinition("http://xamlforge.com/magellan", "Magellan")]
[assembly: XmlnsDefinition("http://xamlforge.com/magellan", "Magellan.Abstractions")]
[assembly: XmlnsDefinition("http://xamlforge.com/magellan", "Magellan.Commands")]
[assembly: XmlnsDefinition("http://xamlforge.com/magellan", "Magellan.Behaviors")]
[assembly: XmlnsDefinition("http://xamlforge.com/magellan", "Magellan.Controls")]
[assembly: XmlnsDefinition("http://xamlforge.com/magellan", "Magellan.Framework")]
[assembly: XmlnsDefinition("http://xamlforge.com/magellan", "Magellan.Views")]

This allows you to reference any Magellan object with a simple reference:

<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:magellan="http://xamlforge.com/magellan" 
    >

The annoying thing about this, though, is you end up with ugly prefixes all over the XAML:

<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:magellan="http://xamlforge.com/magellan" 
    x:Class="Wizard.Views.Shared.Main" 
    >
    <DockPanel>
        <magellan:ZonePlaceHolder ZoneName="Left" DockPanel.Dock="Left" Width="300" />
        <magellan:ZonePlaceHolder ZoneName="Right" DockPanel.Dock="Right" Width="300" />
        <magellan:ZonePlaceHolder ZoneName="Content" />
    </DockPanel>
</UserControl>

Today I had an idea: I can usurp the Microsoft WPF XML namespaces by adding my own controls to them. It would be as simple as changing my XmlnsDefinition attrbutes to:

[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "Magellan")]
[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "Magellan.Abstractions")]
[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "Magellan.Commands")]
[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "Magellan.Behaviors")]
[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "Magellan.Controls")]
[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "Magellan.Framework")]
[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "Magellan.Views")]

Which lets me use this:

<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="Wizard.Views.Shared.Main" 
    >
    <DockPanel>
        <ZonePlaceHolder ZoneName="Left" DockPanel.Dock="Left" Width="300" />
        <ZonePlaceHolder ZoneName="Right" DockPanel.Dock="Right" Width="300" />
        <ZonePlaceHolder ZoneName="Content" />
    </DockPanel>
</UserControl>

Which not only reads nicer, but is also more accessible, since there's no need to manually add an import (ReSharper will add xmlns entries for you, but unfortunately it doesn't recognise XmlnsDefinition attributes).

My initial reaction is that this is evil, but in thinking about it, there are no Magellan classes that would conflict with classes in the WPF XML namespace. And if other libraries had the same names, you could use prefixes for those to differentiate, so that would just work. It also works fine in Blend. So the only problem that could arise is if someone else used this trick. But since it's so evil, I'd be the only one doing it, so there's no problem ;)

What do you think? Would you be disturbed by this, or would you actually find it a better experience?

Edit: It turns out that even if another library used this technique and was referenced, you can still differentiate between them by using an explicit xmlns:xyz reference. So I am not seeing much of a downside.

A picture of me

Welcome, my name is Paul Stovell. I live in Brisbane and work on Octopus Deploy, an automated deployment tool for .NET applications.

Prior to founding Octopus Deploy, I worked for an investment bank in London building WPF applications, and before that I worked for Readify, an Australian .NET consulting firm. I also worked on a number of open source projects and was an active user group presenter. I was a Microsoft MVP for WPF from 2006 to 2013.

02 Jan 2010

Not evil, more readable.

02 Jan 2010

<Rant xmlns="http://xaml.makes.me/angry">

I've done this in my own assemblies as well and yes, it is absolutely evil. But so is the mess they gave us called XAML so it's justified. The fact that we don't have the option to "import" a namespace into the default namespace is so frustrating and it's only worse in Silverlight. In Silverlight this trick won't even work because you can only apply URI's to system assemblies (which even excludes their own toolkit assemblies) and as a result you wind up with just about a prefix per control. And why can't we do this project-wide without copying/pasting a knot of xmlns attributes from view to view?

Yeah yeah I understand that the namespace problems are largely XML's fault but XAML could have worked around it. Sorry... this is one topic that really gets me fired up and is 75% of the reason that I choose WPF over Silverlight whenever possible.

</Rant>

02 Jan 2010

Paul,

Thanks for the post...recently consuming anything XAML related!

My only concern with what you are proposing, aggregating your namespaces in with the Microsoft WPF ones, have to do with traceability and maintenance. I think the better experience would only be short lived, or at best, only for the original developers. I think the concern of confusing custom types with built in types may be bigger once the application rolls into maintenance mode (changes hands, etc).

We use the first technique of of using XmlNsDefinition to map CLR namespaces to more 'friendly' namespaces (less clutter, better identification, etc). This provides us the best of both worlds, cleans up how we import and provides traceability for dependencies. (e.g. where did this class come from?).

Anyways...some thoughts!

Thanks again! Z

Rob
Rob
02 Jan 2010

Paul, I used this technique with Caliburn early on as well. However, I ran into several issues with Blend/VS that caused the designers to fail in certain scenarios. Ultimately, I opted to move to my own XmlnsDefinition. It was a bit sad for me because the dev experience feels so much more organic when the framework doesn't have to specify prefixes everywhere. I'd suggest you test thoroughly with the tooling and be on the lookup for strange bugs reported by users related to design-time support.

02 Jan 2010

As Rob, I've encounter design-time problems in Blend and VS when using this technique... Do you Paul had any similar problems ?

15 Jul 2010

Can you also post the source code for this demo project?

The XAML compiler is still complaining on me.

15 Jul 2010

For

// http://www.paulstovell.com/xmlnsdefinition
_assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "Planerator")_

namespace Planerator
{

    public class Planerator : FrameworkElement
    {

And xaml:

<Grid>
    <Planerator></Planerator>

It will give me:

error MC3074: The tag 'Planerator' does not exist in XML namespace 'http://schemas.microsoft.com/winfx/2006/xaml/presentation'. Line 9 Position 10.

Please help.