Search code examples
silverlightxamlsilverlight-toolkit

Bind to a ListBox of UserControl Elements?


This is not working out for me:

<StackPanel>
    <ListBox x:Name="MyListBox"
        ItemsSource="{StaticResource UserControlsCollection}">
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal" />
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
    </ListBox>
    <UserControl
        Content="{Binding ElementName=MyListBox, Path=SelectedValue}"
        />
</StackPanel>

I get this "item does not fall within the expected range" error at runtime. These are the data:

<toolkit:ObjectCollection x:Key="UserControlsCollection">
    <UserControl Style="{StaticResource UserControlListItemStyle}">
        <Button>One Button</Button>
    </UserControl>
    <UserControl Style="{StaticResource UserControlListItemStyle}">
        <ComboBox>
            <ComboBoxItem Content="One" IsSelected="True" />
            <ComboBoxItem Content="Two" />
            <ComboBoxItem Content="Three" />
        </ComboBox>
    </UserControl>
    <UserControl Style="{StaticResource UserControlListItemStyle}">
        <Rectangle
            Fill="Red"
            Width="120" Height="120"
            />
    </UserControl>
</toolkit:ObjectCollection>

Solution

  • You are trying to display the same FrameworkElements (those in the collection) twice: Once as items in the ListBox, and after selection a second time in the bound UserControl.

    All FrameworkElements can only be hooked in the visual tree once (that is when they fire the loaded event).

    To achieve what you're trying to do you need to separate models and views. The models will be in your collection and can be any type, typically implementing INotifyPropertyChanged or deriving from DependencyObject, and your views could be DataTemplates as resources with the Target attribute being the type of the model.

    Since SL5, any ContentControl with the model as its content (likewise ListBox with the models as elements of the bound collection) will then automatically pick up those DataTemplates if they are in scope. The templates will then be instantiated potentially multiple times for each model.