Thursday, April 08, 2010

Organize XAML Namespace Declarations with XmlnsDefinitionAttribute

Microsoft does it and you can do it, too!

Whenever you need to use a control from an assembly you need to provide an xml namespace for it to avoid any collisions with existing types. By default, you need to specifically reference the namespace for each control you need access to in your XAML.

This might lead to declarations like this in your XAML:

<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:treeView="clr-namespace:MaryKay.SamPortal.Common.UI.TreeView.Views;assembly=MaryKay.SamPortal.Common.UI"
xmlns:infoBar="clr-namespace:MaryKay.SamPortal.Common.UI.InfoBar.Views;assembly=MaryKay.SamPortal.Common.UI"
</UserControl>


This can get ugly pretty fast if you have lots of controls in your XAML view!

However, notice how clean the Microsoft xml namespaces are? You get a lot of controls brought into scope by leveraging those simple namespaces. This is accomplished by using the assembly XmlnsDefinitionAttribute.

From MSDN


Specifies a mapping in an assembly between an XML namespace and a CLR namespace.


Which means it allows us to provide a facade, or an alias, for a namespace, or group of namespaces within an assembly. This makes it much easier to bring all the controls in a control library into scope.

For example, in the MaryKay.SamPortal.Common.UI library, all of the controls are surfaced through the namespace alias “urn:marykay-samportal-common-ui” using XmlnsDefinition in the assemblies AssemblyInfo.cs:

[assembly: XmlnsDefinition("urn:marykay-samportal-common-ui", "MaryKay.SamPortal.Common.UI.InfoBar.Views")]
[assembly: XmlnsDefinition("urn:marykay-samportal-common-ui", "MaryKay.SamPortal.Common.UI.RoleGroupPicker.Views")]
[assembly: XmlnsDefinition("urn:marykay-samportal-common-ui", "MaryKay.SamPortal.Common.UI.BetterPopup")]
[assembly: XmlnsDefinition("urn:marykay-samportal-common-ui", "MaryKay.SamPortal.Common.UI.TextEditor")]
[assembly: XmlnsDefinition("urn:marykay-samportal-common-ui", "MaryKay.SamPortal.Common.UI.Converters")]
[assembly: XmlnsDefinition("urn:marykay-samportal-common-ui", "MaryKay.SamPortal.Common.UI.Documents")]
[assembly: XmlnsDefinition("urn:marykay-samportal-common-ui", "MaryKay.SamPortal.Common.UI.SplashScreen")]
[assembly: XmlnsDefinition("urn:marykay-samportal-common-ui", "MaryKay.SamPortal.Common.UI.TemplateSelector")]
[assembly: XmlnsDefinition("urn:marykay-samportal-common-ui", "MaryKay.SamPortal.Common.UI.ModalDialog")]
[assembly: XmlnsDefinition("urn:marykay-samportal-common-ui", "MaryKay.SamPortal.Common.UI.ConsultantSearch.Views")]

and so forth..

This cleans up our required XAML declarations to simply:

<UserControl
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:commonUI="urn:marykay-samportal-common-ui">
<commonUI:InformationBar DataContext="{Binding InfoBar}"/>
</UserControl>

Which makes our XAML much cleaner and easier to work with. It even supports intellisense!