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/