UserControl как DataTemplate внутри списка

Я хочу повторно использовать мои UserControls в других UserControls как страница или окно как DataTemplates, в этом примере внутри ListBox. Все MVVM.

У меня есть UserControl под названием " CardControl "для отображения простого объекта"Card". Карта имеет два свойства: "ID"и " CardImage". Элементы управления DataContext устанавливаются с помощью XAML. Если я открою этот UserControl в VS или Blend, он покажет мне фиктивную карту, которую я определил в соответствующей ViewModel.

теперь у меня другой UserControl называется "CardSetControl", который должен отображать коллекцию карт. Таким образом, ViewModel имеет одно свойство типа ObservableCollection, называемое "карты".

вот код:

<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>

прочитав тонны статей о MVVM и DataContext / Binding, я все еще не смог заставить его работать. Как вся эта иерархическая вещь USerControls/DataContexts сделана лучшим чистым способом?

3 ответов


для элемента управления ListBox для каждого элемента в источнике элементов создается выводимый элемент ListBoxItem. Элемент задается как DataContext, а ItemTemplate - как шаблон. Поскольку DataContext наследуется, вам не нужно явно устанавливать его, потому что это уже экземпляр карты в вашем DataTemplate.

в этом случае вам не нужно устанавливать DC на CardControl, потому что он установлен для вас.

<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 /> 

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

должно работать на вас.


в вашем примере DataContext на UserControl будет выбранной картой. Она течет в UserControl и его дочерние элементы управления, как и любой другой UIElement получает DataContext родительского контроля.

это будет работать:

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

где CardControl:

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

Спасибо за ваши ответы, но я узнал, что моя проблема была еще одной, о которой я упоминал. Если сделать это так, как вы описали, я вижу, что мои UserControls (CardControl) используются в качестве шаблона для элементов списка, а идентификатор и изображение отображаются правильно.

кроме того, я всегда задавался вопросом, почему ID и изображение могут отображаться, пока я не могу привязаться к некоторым другим свойствам, которые я определил в ViewModel.

сегодня я нашел интересную статью о DataContext в иерархии. Там говорится, что DataContext внутри ListBox не является тем же DataContext, что и на странице, в которой находится ListBox. Я не видел этого раньше, поэтому я подумал, что должен установить DataContext каким-то образом, как я упоминал в вопросе. Теперь я могу привязаться ко всем свойствам.

вот статья: http://blog.thekieners.com/2010/09/08/relativesource-binding-with-findancestor-mode-in-silverlight/