Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

WPF: Merged dictionary parser depends on XML attribute order

0.00/5 (No votes)
13 Aug 2010 2  
Attribute order should not matter in XAML, but sometimes it does...

Does attribute order in XAML matter? It should not, but sometimes it does. The following XAML compiles, but blows up at runtime with “Item has already been added” exception, both in .NET 3.5 and .NET 4.0:

XML
<Window x:Class="MergedDictionaryKeyPosition.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
  <Window.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary>
                <Style TargetType="Button" x:Key="foo" />
                <Style TargetType="Button" x:Key="bar" />
            </ResourceDictionary>
        </ResourceDictionary.MergedDictionaries> 
   </ResourceDictionary>
  </Window.Resources>

  <TextBlock HorizontalAlignment="Center" 
	VerticalAlignment="Center" Text="Hello" />
</Window>

What’s wrong with it? Style elements in resource dictionaries have a special feature: if explicit key is not present, TargetType (in this case typeof(Button)) will be used as a key. This allows overriding default style for a control type. It seems that in this case XAML parser sees TargetType first and ignores the explicit key, thus creating a conflict – it attempts to add two styles under the same key “Button”.

If I put x:Key in front of target type, everything works:

XML
<Window x:Class="MergedDictionaryKeyPosition.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
  <Window.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary>
                <Style x:Key="foo" TargetType="Button" />
                <Style x:Key="bar" TargetType="Button" />
            </ResourceDictionary>
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
  </Window.Resources>

  <TextBlock HorizontalAlignment="Center" 
	VerticalAlignment="Center" Text="Hello" />
</Window>

This rule seems to apply only to merged resource dictionaries. For standalone dictionaries, it is OK to have the key after the target type. The following XAML works:

XML
<Window x:Class="MergedDictionaryKeyPosition.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
  <Window.Resources>
    <ResourceDictionary>
        <Style TargetType="Button" x:Key="foo" />
        <Style TargetType="Button" x:Key="bar" />
    </ResourceDictionary>
  </Window.Resources>

  <TextBlock HorizontalAlignment="Center" 
	VerticalAlignment="Center" Text="Hello" />
</Window>

as does this one:

XML
<Window x:Class="MergedDictionaryKeyPosition.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
  <Window.Resources>
     <Style TargetType="Button" x:Key="foo" />
     <Style TargetType="Button" x:Key="bar" />
  </Window.Resources>

  <TextBlock HorizontalAlignment="Center" 
	VerticalAlignment="Center" Text="Hello" />
</Window>

I am not sure why merged resource dictionaries parser is different from regular resource dictionary parser. Also, the stack trace for the exception is quite different between .NET 3.5 and .NET 4.0, so this code must have been reworked, but the error is exactly the same in both cases. I will post this on the MSDN forum and see whether Microsoft has an answer.

<rant>Unfortunately, from previous experience I know that such things are rarely fixed, 
typical scenario being something like "oh, resource dictionaries are obsolete now, 
in .NET 5 they are replaced with hashed foobars". <img src="http://www.ikriv.com/blog/wp-includes/images/smilies/icon_smile.gif" alt=":)" class="wp-smiley" /></rant>

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here