WPF ResourceDictionary Item has already been added using ComponentResourceKey
Asked Answered
D

3

6

I have the following ResourceDictionary that gets merged into my Themes/Generic.xaml file

<DataTemplate DataType="{x:Type model:RequirementResourceRelation}" x:Key="{x:Static local:Resources.RequirementResourceRelationListTemplateKey}">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>
        <TextBlock MinWidth="35" HorizontalAlignment="Left" Padding="3,0" Text="{Binding Resource.Name, TargetNullValue=Loading...}" />
        <TextBlock Grid.Column="1" Text="-" />
        <TextBlock Grid.Column="2" MinWidth="35" HorizontalAlignment="Left" Padding="3,0" Text="{Binding Path=RelationType, TargetNullValue=Loading...}" TextWrapping="NoWrap" TextTrimming="CharacterEllipsis" />
    </Grid>
</DataTemplate>

<DataTemplate DataType="{x:Type model:RequirementResourceRelation}" x:Key="{x:Static local:Resources.RequirementResourceRelationListTemplate2Key}">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>
        <TextBlock MinWidth="35" HorizontalAlignment="Left" Padding="3,0" Text="{Binding Requirement.Name, TargetNullValue=Loading...}" />
        <TextBlock Grid.Column="1" Text="-" />
        <TextBlock Grid.Column="2" MinWidth="35" HorizontalAlignment="Left" Padding="3,0" Text="{Binding Path=RelationType, TargetNullValue=Loading...}" TextWrapping="NoWrap" TextTrimming="CharacterEllipsis" />
    </Grid>
</DataTemplate>

I'm trying to create two different data templates for the same DataType with different ComponentResourceKey. As you can see one of the keys has a 2 appended to it.

In my local:Resources class I have the following which is the ComponentResourceKey I'm using.

    public static ComponentResourceKey RequirementResourceRelationListTemplateKey {
        get {
            return new ComponentResourceKey(typeof(Resources), "RequirementResourceRelationListTemplate");
        }
    }

    public static ComponentResourceKey RequirementResourceRelationListTemplate2Key {
        get {
            return new ComponentResourceKey(typeof(Resources), "RequirementResourceRelationListTemplate2");
        }
    }

This works if I have only one of the DataTemplates in there, but once I add the second one I get an exception that says:

Item has already been added. Key in dictionary: 'DataTemplateKey(HR.TrackingTool.Model.RequirementResourceRelation)'  Key being added: 'DataTemplateKey(HR.TrackingTool.Model.RequirementResourceRelation)'
   at System.Collections.Hashtable.Insert(Object key, Object nvalue, Boolean add)
   at System.Collections.Hashtable.Add(Object key, Object value)
   at System.Windows.ResourceDictionary.SetKeys(IList`1 keyCollection, IServiceProvider serviceProvider)
   at System.Windows.ResourceDictionary.SetDeferrableContent(DeferrableContent deferrableContent)
   at System.Windows.Baml2006.WpfSharedBamlSchemaContext.<Create_BamlProperty_ResourceDictionary_DeferrableContent>b__168(Object target, Object value)
   at System.Windows.Baml2006.WpfKnownMemberInvoker.SetValue(Object instance, Object value)
   at MS.Internal.Xaml.Runtime.ClrObjectRuntime.SetValue(XamlMember member, Object obj, Object value)
   at MS.Internal.Xaml.Runtime.ClrObjectRuntime.SetValue(Object inst, XamlMember property, Object value)

It seems that the ResourceDictionary ignores the key when adding a DataTemplate. Does the ResourceDictionary ignore the key property when it's using a ComponentRelationKey ?

Any way around this exception ?

Thanks, Raul

Description answered 29/7, 2010 at 21:49 Comment(0)
M
5

If you reference your DataTemplate by key, can't you just leave out the DataType-specification? Without DataType="{x:Type model:RequirementResourceRelation}" (which is apparently the key for the added item) your x:Key should be used as the key.

Militarist answered 30/7, 2010 at 12:20 Comment(3)
Awesome work around. I have submitted this as a bug to Microsoft. connect.microsoft.com/VisualStudio/feedback/details/581761/…Description
This bug is still active. Incredible!! I am adding two styles for a TextBlock to an app resources dictionary. Stuck with this bug. Completely, utterly frustrating. I want to smash my screen with my keyboard. Microsoft blows. Period.Varipapa
That being said, this fixed it for me. I am losing too much hair.Varipapa
K
13

Apparently the issue is as stated, sort of. The order of the declaration of the style matters.

When the first attribute for two styles for the same TargetType is the TargetType e.g.

<Style TargetType="{x:Type TextBlock}" x:Key="_defaultRuleTextBlockStyle">
<Style TargetType="{x:Type TextBlock}" x:Key="_tinySourceCodeTextBlockStyle">

then you get the error. It seems to ignore the Key: attribute and as stated uses the TargetType value as the dictionary key e.g. "{x:Type TextBlock}"

When the first element of two styles for the same TargetType is the x:Key, then you do not, as shown below.

<Style x:Key="_defaultRuleTextBlockStyle" TargetType="{x:Type TextBlock}">
<Style x:Key="_tinySourceCodeTextBlockStyle" TargetType="{x:Type TextBlock}">

Doesn't matter if you move the crap around I guess. WOrd to the wise, always start with the x:Key, but this is a really stupid error.

Keratin answered 7/11, 2013 at 16:39 Comment(3)
Best answer in IMO. Had me stuck for a while and doubting my whole understanding of WPF. Didn't realise that the order of the parameters in XAML ever made a difference but apparently it does.Jinn
I would NEVER have been able to figure this out on my own. Well done!Electrothermics
Nice find. Attribute order shouldn't matter (should it)? Didn't think I was doing anything wrong.Jinn
M
5

If you reference your DataTemplate by key, can't you just leave out the DataType-specification? Without DataType="{x:Type model:RequirementResourceRelation}" (which is apparently the key for the added item) your x:Key should be used as the key.

Militarist answered 30/7, 2010 at 12:20 Comment(3)
Awesome work around. I have submitted this as a bug to Microsoft. connect.microsoft.com/VisualStudio/feedback/details/581761/…Description
This bug is still active. Incredible!! I am adding two styles for a TextBlock to an app resources dictionary. Stuck with this bug. Completely, utterly frustrating. I want to smash my screen with my keyboard. Microsoft blows. Period.Varipapa
That being said, this fixed it for me. I am losing too much hair.Varipapa
G
1

Move the DataTemplate(s) inside the <Resources> element of another control.

In Silverlight this worked just fine:

<ResourceDictionary     
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 >
    <!--Template 1-->
    <DataTemplate DataType="VMType" x:Key="Template1">
        ...
    </DataTemplate>
    <!--Template 2-->
    <DataTemplate DataType="VMType" x:Key="Template2">
        ...
    </DataTemplate>
    <!--Control Style, references the two templates above-->
    <Style TargetType="ControlType">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ControlType">
                    <Grid Background="White" Margin="0">          
                        ...
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

BUT in WPF, I had to move the 3 templates inside the control:

<ResourceDictionary     
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 >
    <Style TargetType="ControlType">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ControlType">
                    <Grid Background="White" Margin="0">          
                        <!--MOVED HERE INSTEAD OF THE ROOT-->              
                        <Grid.Resources>
                            <!--Template 1-->
                            <DataTemplate DataType="VMType" x:Key="Template1">
                                ...
                            </DataTemplate>
                            <!--Template 2-->
                            <DataTemplate DataType="VMType" x:Key="Template2">
                                ...
                            </DataTemplate>
                        </Grid.Resources>
                        ...
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

Now it works in both WPF and Silverlight without the error.

Gigigigli answered 30/11, 2012 at 12:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.