Click here to Skip to main content
15,882,063 members
Articles / Desktop Programming / XAML

WPF: Merged dictionary parser depends on XML attribute order

Rate me:
Please Sign up or sign in to vote.
0.00/5 (No votes)
13 Aug 2010Apache1 min read 11.1K   5  
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>
This article was originally posted at http://www.ikriv.com/blog?p=543

License

This article, along with any associated source code and files, is licensed under The Apache License, Version 2.0


Written By
Technical Lead Thomson Reuters
United States United States
Ivan is a hands-on software architect/technical lead working for Thomson Reuters in the New York City area. At present I am mostly building complex multi-threaded WPF application for the financial sector, but I am also interested in cloud computing, web development, mobile development, etc.

Please visit my web site: www.ikriv.com.

Comments and Discussions

 
-- There are no messages in this forum --