Conditional List itemtemplate or datatemplate in WPF
Just specifying DataTemplates
in the Resources
with the respective DataType
is enough, e.g.
<ListView ItemsSource="{Binding Data}"> <ListView.Resources> <!-- Do NOT set the x:Key --> <DataTemplate DataType="{x:Type local:Employee}"> <TextBlock Text="{Binding Name}" Foreground="Blue"/> </DataTemplate> <DataTemplate DataType="{x:Type local:Machine}"> <TextBlock Text="{Binding Model}" Foreground="Red"/> </DataTemplate> </ListView.Resources></ListView>
(Note that DataTemplate.DataType
can also be used for implicit XML data templating (see docs), the property type for that reason is not System.Type
, so unlike in Style.TargetType
you have to use x:Type
to reference a CLR-type. If you just enter a string it will not be converted to a type.)
You might also want to look into CompositeCollections
, to get clean merged lists of varying types.
Sample data i used:
ObservableCollection<Employee> data = new ObservableCollection<Employee>(new Employee[]{ new Employee("Hans", "Programmer") , new Employee("Elister", "Programmer") , new Employee("Steve", "GUI Designer") , new Employee("Stephen", "GUI Designer") , new Employee("Joe", "Coffee Getter") , new Employee("Julien", "Programmer") , new Employee("John", "Coffee Getter") ,});ObservableCollection<Machine> data2 = new ObservableCollection<Machine>(new Machine[]{ new Machine("XI2", String.Empty), new Machine("MK2-xx", String.Empty), new Machine("A2-B16", String.Empty),});CompositeCollection cc1 = new CompositeCollection();cc1.Add(new CollectionContainer() { Collection = data });cc1.Add(new CollectionContainer() { Collection = data2 });Data = cc1;
One option is to create a DataTemplateSelector in your code:
public class QueueDisplayDataTemplateSelector : DataTemplateSelector{ public override DataTemplate SelectTemplate(object item, System.Windows.DependencyObject container) { var listBoxItem = item as JobQueueListBoxItem; var resourceName = String.Empty; switch (listBoxItem.JobQueueListBoxItemType) { case JobQueueListBoxItemType.QueuedJob : resourceName = "DataTemplateQueuedJob"; break; case JobQueueListBoxItemType.TransferWorker : resourceName = "DataTemplateTransferWorker"; break; default: throw new InvalidOperationException(string.Format("There is no corresponding list box template for {0}", listBoxItem.JobQueueListBoxItemType)); } var element = container as FrameworkElement; return element.FindResource(resourceName) as DataTemplate; }}
This would then be declared in your XAML as a resource
<ResourceDictionary> <local:QueueDisplayDataTemplateSelector x:Key="QueueDisplayDataTemplateSelector" />
And then you would assign this to you list box:
<ListBox ItemsSource="{Binding ListBoxContents}" ItemTemplateSelector="{StaticResource QueueDisplayDataTemplateSelector}" >