Я думаю, вы спрашиваете о соответствии шаблонов данных.
Если вы хотите, чтобы привязка выбрала шаблон данных, который он использует для представления объекта во время выполнения, самый простой способ - поместить шаблоны в словарь ресурсов и установить их свойство DataType
, например ::
.
<ItemsControl ItemsSource="{Binding Things}">
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type Thing1}">
...
</DataTemplate>
<DataTemplate DataType="{x:Type Thing2}">
...
</DataTemplate>
</ItemsControl.Resources>
</ItemsControl>
Теперь, если ваша модель представления вместо свойства Names
имеет свойство Things
:
public ObservableCollection<object> Things { get; set; }
вы можете заполнить коллекцию объектами Thing1
и Thing2
, и ItemsControl
предоставит каждому соответствующий шаблон.
Если вы хотите выбрать другой шаблон, основанный на значении свойства, также есть несколько способов сделать это. Одним из них является написание DataTemplateSelector , которое дает вам очень детальный контроль над тем, какой шаблон выбирается, но требует от вас фактически кодировать (и тестировать, и документировать) что-то.
Другой способ - использовать стили для отображения и скрытия контента на основе триггера. На самом деле это не выбирает разные шаблоны как таковые, но выполняет более или менее одно и то же. Поместите это в свой шаблон элемента, и он будет отображать один набор контента, когда Name
- «Thing1», а другой, когда Name
- «Thing2».
A очень хорошая особенность этого подхода в том, что в отличие от выбора шаблона, он динамический: если значение свойства Name
изменяется во время выполнения (и ваша модель представления реализует уведомление об изменении свойства), так будет и то, что появляется на виде.
<StackPanel>
<ContentControl>
<ContentControl.Style>
<Style TargetType="ContentControl">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Name}" Value="Thing1">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
<!-- content to display when Name = Thing1 goes here -->
</ContentControl>
<ContentControl>
<ContentControl.Style>
<Style TargetType="ContentControl">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Name}" Value="Thing2">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
<!-- content to display when Name = Thing2 goes here -->
</ContentControl>
</StackPanel>
Наконец, , если вы на самом деле пытаетесь создать разные модели представлений в своей коллекции на основе значений строки в коллекции Names
, вы делаете это в модели представлений. Вы можете сделать это:
public IEnumerable<object> ViewModels
{
get
{
foreach (string name in Names)
{
switch (name)
{
case "Thing1": yield return new Thing1ViewModel(name);
case "Thing2": yield return new Thing2ViewModel(name);
default: throw new InvalidOperationException();
}
}
}
}
Если значения в Names
изменяются во время выполнения, у вас возникает существенно более сложная проблема: вам нужно реализовать ViewModels
как свойство ObservableCollection<object>
, и вам, возможно, придется пойти так далеко, чтобы обработать сбор - изменять события в коллекции Names
и обновлять коллекцию ViewModels
всякий раз, когда элемент в Names
добавляется, удаляется или изменяется.