views:

1535

answers:

3

I want to add a single model object that has been instantiated once in XAML, and add it to two different collections (in xaml).

The following code renders fine in Blend's Design Time, but I get the following errors at run time:

For "Post1"
Object of type 'WpfBlog.Models.Tag' cannot be converted to type 'System.Collections.ObjectModel.ObservableCollection`1[WpfBlog.Models.Tag]'. Error at object 'WpfBlog.Admin' in markup file 'WpfBlog;component/Admin.xaml' Line XX Position YY.

If I comment out "Post1", I'll get this error on "Post2"
Cannot add element to property 'Tags', because the property can have only one child element if it uses an explicit collection tag. Error at object 'System.Windows.StaticResourceExtension' in markup file 'WpfBlog;component/Admin.xaml' Line AA Position BB.

<Window.Resources>
    <model:Tag x:Key="TDD" Name="TDD" ForeColor="Black" BackColor="White" />
    <model:Tag x:Key="Agile" Name="Agile" ForeColor="White" BackColor="Black" />
    <model:Tag x:Key="Waterfail" Name="Waterfail" ForeColor="Red" BackColor="White" />
</Window.Resources>
<Window.DataContext>
    <local:AdminViewModel>
     <local:AdminViewModel.AllTags>
            <StaticResource ResourceKey="TDD"/>
            <StaticResource ResourceKey="Agile"/>
            <StaticResource ResourceKey="Waterfail"/>
        </local:AdminViewModel.AllTags>
  <local:AdminViewModel.Posts>
            <local:PostViewModel Title="Post1">
                <local:PostViewModel.Tags>
                    <StaticResource ResourceKey="TDD" />
                </local:PostViewModel.Tags>
            </local:PostViewModel>
            <local:PostViewModel Title="Post2">
                <local:PostViewModel.Tags>
     <StaticResource ResourceKey="TDD" />
                    <StaticResource ResourceKey="Agile" />
                    <StaticResource ResourceKey="Waterfail" />
                </local:PostViewModel.Tags>
            </local:PostViewModel>
        </local:AdminViewModel.Posts>
    </local:AdminViewModel>
<Window.DataContext>

The following code compiles and runs fine, but two tags named "TDD" get created, so if I try to rename the tag, I have to do it for all of the posts, instead of just the one Tag object.

<Window.Resources>
    <model:Tag x:Key="TDD" Name="TDD" ForeColor="Black" BackColor="White" />
    <model:Tag x:Key="Agile" Name="Agile" ForeColor="White" BackColor="Black" />
    <model:Tag x:Key="Waterfail" Name="Waterfail" ForeColor="Red" BackColor="White" />
</Window.Resources>
<Window.DataContext>
    <local:AdminViewModel>
     <local:AdminViewModel.AllTags>
            <StaticResource ResourceKey="TDD"/>
            <StaticResource ResourceKey="Agile"/>
            <StaticResource ResourceKey="Waterfail"/>
        </local:AdminViewModel.AllTags>
  <local:AdminViewModel.Posts>
            <local:PostViewModel Title="Post1">
                <local:PostViewModel.Tags>
                    <model:Tag Name="TDD" ForeColor="Black" BackColor="White" />
                </local:PostViewModel.Tags>
            </local:PostViewModel>
            <local:PostViewModel Title="Post2">
                <local:PostViewModel.Tags>
           <model:Tag Name="TDD" ForeColor="Black" BackColor="White" />
           <model:Tag Name="Agile" ForeColor="White" BackColor="Black" />
           <model:Tag Name="Waterfail" ForeColor="Red" BackColor="White" />
                </local:PostViewModel.Tags>
            </local:PostViewModel>
        </local:AdminViewModel.Posts>
    </local:AdminViewModel>
<Window.DataContext>

Any ideas? I'd be able to ignore it and work around it if Blend didn't render it correctly, but it does!

A: 

This is very similar to the problem described in this question, I think.

The solution should be to add an x:Shared="False" attribute to your <model:Tag> elements. That tells WPF not to share a single instance each time one is referenced, and instead to create new instances of them.

Matt Hamilton
A: 

@Matt-

Thanks for taking the time to comment, but what I want is a single version of the Tag object (I don't want new versions of the object each time the resource is referenced). The problem seems to be that wpf runtime (not blend) doesn't like me adding a static resource to an ObservableCollection in XAML.

viggity
+2  A: 

I was able to avoid the problem by explicitly initializing a new collection within the Tags property. Something like this:

<local:PostViewModel Title="Post1">
  <local:PostViewModel.Tags>
     <model:TagCollection>
        <StaticResource ResourceKey="TDD" />
     </model:TagCollection>
  </local:PostViewModel.Tags>

Obviously, this is only possible if you allow your Tags property to be writable.

Samuel Jack