0
votes

First, my scenario. I have a ViewModel with a public property Items of type ObservableCollection<UserControl> which contains UserControls that I want to display using <ItemsControl ItemsSource="{Binding Items}" />.

I get the UserControls using Application.Current.TryFindResource("ControlKey") as UserControl. When every resource has a different x:Key, everything works fine. However, when I add more UserControls to Items with the same x:Key, the ItemsControl displays only one of the UserControls with identical x:Key even though all of the UserControls are present in Items.

In example, I add items to the collection like so:

Items.Add(Application.Current.TryFindResource("Filter1") as UserControl);
Items.Add(Application.Current.TryFindResource("Filter1") as UserControl);
Items.Add(Application.Current.TryFindResource("Filter2") as UserControl);

Only two controls show up in the ItemsControl, one with x:Key "Filter1" and the one with "Filter2". The second UserControl with x:Key "Filter1" is not shown.

What am I missing? Thanks a lot.

1

1 Answers

1
votes

Each element in a logical tree can be used only once. You are trying to use the same element twice. Check out the following example:

<Window x:Class="SO.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <Button x:Key="btn">Hello</Button>
    </Window.Resources>
    <StackPanel>
        <ContentControl Content="{StaticResource btn}" />
        <ContentControl Content="{StaticResource btn}" />
    </StackPanel>
</Window>

If you try to run this code, you'll get an exception, during the assignment of the Content property. The inner exception will tel you that the element is already placed somewhere else in the tree.

You should create a new UserControl instance for each item in the collection (hint: the keyword 'new' has to be used somewhere).

EDIT (reply to @Jan comment): @Jan, while using reflection you could create new instances of object of a given type - this isn't the preferred design. Forget about putting instances of your User Control in the application dictionary. Just have the classes defined. Then instead of:

Items.Add(Application.Current.TryFindResource("Filter1") as UserControl);
Items.Add(Application.Current.TryFindResource("Filter1") as UserControl);

just do:

Items.Add( new Filter1() );
Items.Add( new Filter1() );

If you have is the string 'Filter1' as a variable - implement a utility method 'instantiate' - within that function either have a switch statement, or use reflection:

Items.Add( instantiate( key ) );

private UserControl instantiate( string key ) {
    ...
}