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:
<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:
<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:
<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:
<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 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”. 🙂 </rant>