#c# #wpf #datatemplate
#c# #wpf #datatemplate
Вопрос:
Вот мой конкретный сценарий.
Окно ресурсов кода:
...
<Window.Resources>
<ResourceDictionary>
<CollectionViewSource x:Key="AdditionalStringData" Source="{Binding ViewModelObservableCollection_String}"/>
<CollectionViewSource x:Key="AdditionalCustomObjectData" Source="{Binding ViewModelObservableCollection_CustomObject}"/>
<ResourceDictionary.MergedDictionaries>
...
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
...
Часть, в которой мне нужно отобразить коллекцию:
...
<StackPanel>
<ItemsControl>
<ItemsControl.ItemsSource>
<CompositeCollection>
<TextBlock Text="{Binding ViewModelTextProperty}"/>
<Button Command="{Binding ViewModelRelayCommand}">Command</Button>
<CollectionContainer Collection="{Binding Source={StaticResource AdditionalStringData}}" />
<CollectionContainer Collection="{Binding Source={StaticResource AdditionalCustomObjectData}}" />
</CompositeCollection>
</ItemsControl.ItemsSource>
</ItemsControl>
</StackPanel>
...
ViewModel (предположим, что он привязан правильно)
...
private string ViewModelTextProperty { get; set; } = "Sample Text";
public RelayCommand ViewModelRelayCommand { ... }
private ObservableCollection<string> ViewModelObservableCollection_String { get; set; } = new ObservableCollection<string>();
private ObservableCollection<CustomObject> ViewModelObservableCollection_CustomObject { get; set; } = new ObservableCollection<CustomObject>();
...
Класс CutomObject (возможно, он не нужен для отображения):
...
public class CustomObject
{
public string firstString;
public string secondString;
public CustomObject()
{
...
}
...
}
...
Предположим, что ObservableCollection
s имеет правильное содержимое.
Мой вопрос: как я могу правильно отобразить коллекцию? Вот критерии:
- В первой строке будет текстовый блок с текстом внутри него с надписью «Образец текста»
- Далее находится кнопка с надписью «Command»
- Следующие строки (столько, сколько
ViewModelObservableCollection_String
элементов) являются текстовыми блоками. Его текст должен быть значением отдельного элементаViewModelObservableCollection_String
. - Следующие строки (столько, сколько
ViewModelObservableCollection_CustomObject
элементов) являются текстовыми полями. Его текст должен быть значением отдельного элементаViewModelObservableCollection_CustomObject
(конкатенацияfirstString
иsecondString
).
Как вы можете видеть, содержимое StackPanel представляет собой объединение нескольких коллекций с разными DataTemplate
.
Пожалуйста, попросите разъяснений, если что-то недостаточно ясно.
Ответ №1:
-
Используйте
DataTrigger
insideItemTemplate
для измененияControlTemplate
Control
используемого при сравненииType
. Для этого используйте конвертер, который вернет тип.или,
-
Используйте
ContentControl
какItemTemplate
. -
Определите
DataTemplate
указаниеDataType
в нем.ContentControl
автоматически выберет подходящийDataTemplate
для негоContentTemplate
.
Второй подход (рекомендуется)
<Window.Resources>
<ResourceDictionary>
...
<DataTemplate DataType="{x:Type sys:String}">
<TextBlock Background="ForestGreen" Text="{Binding .}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:CustomObject}">
<StackPanel Orientation="Horizontal">
<TextBlock Background="Red" Text="{Binding firstString}"/>
<TextBlock Background="Red" Text="{Binding secondString}"/>
</StackPanel>
</DataTemplate>
</ResourceDictionary>
</Window.Resources>
<ItemsControl>
...
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentControl Content="{Binding .}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
...
</ItemsControl>
Комментарии:
1. Спасибо. Не могли бы вы подробнее рассказать об этом? Я относительно новичок в WPF.
2. Я думаю, ваше второе предложение проще. Не могли бы вы предоставить пример кода? Если нет, пожалуйста, дайте мне какую-нибудь ссылку на это.