Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conditional List itemtemplate or datatemplate in WPF

Tags:

This may be an obvious question, but I think there may well be multiple ways to implement it, so not only will this be useful to me, hopefully it will be useful to others.

Essentially I'm looking for the best way to implement a list view that can accept different types of objects and then renders them with the appropriate item/data template for that object.

So for example... we have a standard product list view, and when we view different categories the business has decided it would like to show a different item template style for each different category.

The main reason for asking this here, is to avoid a nasty hacky solution and discover a good clean method instead.

Hopefully I've provided enough information, let me know if you need more.

like image 447
ocodo Avatar asked Apr 13 '11 04:04

ocodo


2 Answers

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> 

Screenshot

(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; 
like image 188
H.B. Avatar answered Jan 04 '23 00:01

H.B.


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}"              > 
like image 31
Andrew Shepherd Avatar answered Jan 04 '23 01:01

Andrew Shepherd