다음을 통해 공유


Namespaces in Xaml

If you’re really into Xml conformance, and you’ve really wondered how Xaml uses Xml namespaces, read on; I can cover the most relevant details in 1160 words or less …

 

Namespaces on tags

 

(I’m using the term “tag” here instead of the more correct term “element”, so that I don’t get confused with WPF element objects.)

 

In the W3C Namespaces for XML recommendation, it’s valid for a tag not to be in any namespace; to have no “namespace name”. In Xaml, it’s not. Or rather it’s mostly not; it’s OK if the XML is hiding in a CData section, or in an XData section such as:

 

<Page   

    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"

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

  <Page.DataContext>

    <XmlDataProvider>

      <x:XData>

        <BookList xmlns="">

          <!-- No default namespace name in this scope -->

          <Book Name='Harry Potter and the Deathly Hollows'/>

          <Boot Name='Mark Twain: A Life' />

        </BookList>

      </x:XData>

    </XmlDataProvider>

  </Page.DataContext>

  <ListBox ItemsSource='{Binding XPath=BookList/*}'>

    <ListBox.ItemTemplate>

      <DataTemplate>

        <TextBlock Text='{Binding XPath=@Name}' />

      </DataTemplate>

    </ListBox.ItemTemplate>

  </ListBox>

</Page>

 

... But generally tags must be in a namespace. That because, when Xaml is mapping tags to types, it needs to identify and locate the exact Type. There’s two ways this mapping is done. The really obvious way is for the namespace name URI to use the “clr-namespace” scheme. In this case, the CLR namespace and assembly of the type are specified in the Xaml, such as in the following mappings to the mscorlib.dll assembly for the System.String and System.Collections.ArrayList types:

 

<Page   

    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"

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

    xmlns:sys="clr-namespace:System;assembly=mscorlib"

    xmlns:collections="clr-namespace:System.Collections;assembly=mscorlib" >

  <Page.DataContext>

    <collections:ArrayList>

      <sys:String>Hello</sys:String>

      <sys:String>World</sys:String>

    </collections:ArrayList>

  </Page.DataContext>

  <ListBox ItemsSource='{Binding}' />

</Page>

 

The other way to map tags to types is to match up the namespace name with an assembly that has a corresponding [XmlnsDefinition] assembly attribute. For example, in another post, I put the XmlnsDefinition attribute in my code like this:

 

[assembly: System.Windows.Markup.XmlnsDefinition(

       "https://blogs.msdn.com/mikehillberg/archive/2006/09/27/XamlInspiredMarkup.aspx",

         "EmployeeDatabase")]

namespace EmployeeDatabase

{

    public class Employee

    {

        private AddressInformation _contactInformation;

        public AddressInformation ContactInformation

        {

            get { return _contactInformation; }

            set { _contactInformation = value; }

        }

    }

    ...

 

… and then I referenced that type by using the matching namespace name in my markup:

 

<Employee Name="Rob" Title="President"

          xmlns="https://blogs.msdn.com/mikehillberg/archive/2006/09/27/XamlInspiredMarkup.aspx">

  <Employee.ContactInformation>

    <AddressInformation OfficePhone="123-4567" CellPhone="765-4321" Blog="https://rrelyea.spaces.live.com" />

  </Employee.ContactInformation>

  ...

 

 

Namespaces on other type references

 

More generally than just tags, anywhere in Xaml where a string refers to a type, it’s interpreted in the same way. Specifically, any value that references a Type is treated as a QName. A QName is a name that may or may not have a namespace prefix on it. If a QName doesn’t have a prefix, it’s usually interpreted to have the default namespace name. (If an attribute name doesn’t have a prefix it’s not in the default namespace, but more on that later.)

 

For example, in the following markup, the x:Static markup extension refers to a Class.Property value, so it interprets ‘SystemColors’ (the Class) to be in the default namespace:

 

<Page   

    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"

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

  <Button Background='{x:Static SystemColors.ControlBrush}'>Click</Button>

</Page>

 

Or, using a non-default namespace, you can have the equivalent:

 

<wpf:Page   

    xmlns:wpf="https://schemas.microsoft.com/winfx/2006/xaml/presentation"

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

  <wpf:Button Background='{x:Static wpf:SystemColors.ControlBrush}'>Click</wpf:Button>

</wpf:Page>

 

 

Unprefixed attribute names

 

Attributes are a bit more interesting and non-obvious than tags or other QNames.

 

Whereas for tags, an unprefixed tag name is interpreted to be in the default namespace, unprefixed attributes are by definition not in any namespace. The first time I encountered that was when I was watching some XML get parsed by XmlReader. When an unprefixed attribute went by, the NamespaceURI property of the reader was null. I thought it was a bug. But it actually makes sense if you think about this example:

 

<RandomThings xmlns="https://blogs.msdn.com/mikehillberg/NamespacesInXaml">

  <Molecule Formula="H20" State="Liquid" />

  <Address City="San Francisco" State="CA" />

</RandomThings>

 

Here you have two unprefixed attributes named “State”, but they have different semantics, and more importantly they have distinct sets of valid values: one has to be either liquid, solid, or gas; the other has to be CA, WA, NY, MI, FL, OH, etc. So while the Molecule and Address tags both have the same namespace name (“https://blogs.msdn.com/mikehillberg/NamespacesInXaml”), it wouldn’t make sense to consider the two State attributes to be in the same namespace. And that’s why in the XML namespaces recommendation the State attributes have no namespace name; “interpretation of unprefixed attributes is determined by the element on which they appear”.

 

And when you think about Xaml being used to map XML to types and properties, that makes even more sense. That’s because you encounter the same rules in a class definition; two different classes can have properties with the same name that have different semantics and types. (A “Molecule” class and an “Address” class could both have un-related “State” properties.)

 

Thus in this example there’s no namespace prefix on the Background attribute, but we know it references the Button.Background property:

 

<wpf:Page xmlns:wpf="https://schemas.microsoft.com/winfx/2006/xaml/presentation">

  <wpf:Button Background='Red'>Click</wpf:Button>

</wpf:Page>

 

That’s a “standard” property, though. “Attached” properties are more interesting. For example, in the following, Canvas.Top is an attached property; it’s defined by Canvas, not by Button, despite being set on the Button tag:

 

<Page xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"

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

  <Canvas>

    <Button Canvas.Top='100'>Click</Button>

  </Canvas>

</Page>

 

Since ‘Canvas’ is a reference to a type, it's expanded name uses the default namespace when no prefix is specified. Therefore in this case it has the default namespace name (“https://schemas.microsoft.com/winfx/2006/xaml/presentation”). Or, to make everything explicit again:

 

<wpf:Page xmlns:wpf="https://schemas.microsoft.com/winfx/2006/xaml/presentation"

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

  <wpf:Canvas>

    <wpf:Button wpf:Canvas.Top='100' >Click</wpf:Button>

  </wpf:Canvas>

</wpf:Page>

 

 

Prefixed attribute names

 

If you do put a prefix on an attribute for a standard property, and it maps to the same namespace name, then it behaves functionally equivalent to the attribute without the prefix. For example, this markup:

 

<wpf:Page xmlns:wpf="https://schemas.microsoft.com/winfx/2006/xaml/presentation">

  <wpf:Button Background='Red'>Click</wpf:Button>

</wpf:Page>

 

… is different only in syntax (not function) from this markup, where the Background attribute now has a prefix:

 

<wpf:Page xmlns:wpf="https://schemas.microsoft.com/winfx/2006/xaml/presentation">

  <wpf:Button wpf:Background='Red'>Click</wpf:Button>

</wpf:Page>

 

You can even give the attribute a different prefix, as long as it has the same namespace name (the URI):

 

<wpf:Page

    xmlns:wpf="https://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:wpf2="https://schemas.microsoft.com/winfx/2006/xaml/presentation" >

  <wpf:Button wpf2:Background='Red'>Click</wpf:Button>

</wpf:Page>

 

… But if the namespace names are different, you’ll get an error:

 

<wpf:Page

     xmlns:wpf="https://schemas.microsoft.com/winfx/2006/xaml/presentation"

     xmlns:wpf2="SomethingElse" >

  <!-- Invalid -->

  <wpf:Button wpf2:Background='Red'>Click</wpf:Button>

</wpf:Page>

 

For attached properties, as noted above, the class part of an attached property attribute name is interpreted as a QName, and so the prefix is used to determine the namespace name. The namespace name of the tag is irrelevant.

 

Built-in Xaml attributes

 

Finally, in Xaml there are a few built-in attributes: Key, Name, and Uid. For example, Key is used to provide the key for a dictionary item, such as the ‘myBrush’ here (Page.Resources is a dictionary):

 

<Page

    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"

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

  <Page.Resources>

    <SolidColorBrush x:Key='myBrush'>Red</SolidColorBrush>

  </Page.Resources>

  <Rectangle Width='100' Height='100' Fill='{StaticResource myBrush}' />

</Page>

 

These attributes are global and always must have a prefix. For example, if you modify that example so that ‘x:’ is now the default namespace name, the example becomes invalid:

 

<wpf:Page

    xmlns:wpf="https://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns="https://schemas.microsoft.com/winfx/2006/xaml" >

  <wpf:Page.Resources>

    <wpf:SolidColorBrush Key='myBrush'>Red</wpf:SolidColorBrush>

  </wpf:Page.Resources>

  <wpf:Rectangle Width='100' Height='100' Fill='{wpf:StaticResource myBrush}' />

</wpf:Page>

 

… This is invalid because Key is an unprefixed attribute, so it’s interpreted to be a standard property on SolidColorBrush, rather than being interpreted as in the default namespace (and there is no SolidColorBrush.Key property).

 

 

One last thing

 

One last place where Xaml uses XML namespaces is in the Markup Compatibility feature. But this post is already long enough. See Rob’s blog or MSDN for interesting reading.

Comments

  • Anonymous
    May 16, 2007
    Mike Hillberg has an excellent post on how XML namespaces work in XAML. It's a good refresher if it's