UserControl as DataTemplate inside ListBox

pDEV picture pDEV · Sep 12, 2011 · Viewed 21.6k times · Source

I want to reuse my UserControls in other UserControls like page or window as DataTemplates, in this example inside a ListBox. Everything is MVVM.

I've a UserControl called "CardControl" to display a simple object "Card". Card has two Properties, "ID" and "CardImage". The controls DataContext is set via XAML. If I open this UserControl in VS or Blend it shows me the dummy Card that I have defined in the corresponding ViewModel.

Now I have another UserControl called "CardSetControl", which should display a collection of Cards. So the ViewModel has one property of type ObservableCollection<Card> called "Cards".

Here is the code:

<ListBox x:Name="MyList" ItemsSource="{Binding CardSet.Cards}">
  <ListBox.ItemTemplate>
    <DataTemplate>
      <StackPanel>

        <!-- WORKING, but not what i want -->
        <TextBlock Text="{Binding ID}" /> // would display ID of Card
        <Image Source="{Binding Image}" /> // would display Image of Card

        <!-- NOT WORKING, but this is how i want it to work -->
        <UserControls:CardControl DataContext="{Binding "Current listbox item as DataContext of CardControl???"}" />

      </StackPanel>
    </DataTemplate>
  </ListBox.ItemTemplate>
</ListBox>

After reading tons of articles about MVVM and DataContext/Binding I still didn't get it to work. How is this whole hierarchical USerControls/DataContexts thing done the best clean way?

Answer

user1228 picture user1228 · Sep 12, 2011

In your example, the DataContext of the UserControl would be the currently selected Card. It flows into the UserControl and its child controls like any other UIElement receives the DataContext of its parent control.

This would work:

<ListBox x:Name="MyList" ItemsSource="{Binding CardSet.Cards}">
  <ListBox.ItemTemplate>
    <DataTemplate>
        <UserControls:CardControl />
    </DataTemplate>
  </ListBox.ItemTemplate>
</ListBox>

Where CardControl is:

<UserControl x:Class="MySolution.CardControl" 
             OtherProperties="Not shown to keep this example small">
      <StackPanel>
        <TextBlock Text="{Binding ID}" /> 
        <Image Source="{Binding Image}" />
      </StackPanel>
</UserControl>