Подтвердить что ты не робот

Условный список itemtemplate или datatemplate в WPF

Это может быть очевидный вопрос, но я думаю, что может быть много способов его реализации, поэтому это не только будет полезно для меня, мы надеемся, что это будет полезно для других.

По сути, я ищу лучший способ реализовать представление списка, которое может принимать разные типы объектов, а затем отображает их с соответствующим шаблоном элемента/данных для этого объекта.

Итак, например... у нас есть стандартное представление списка продуктов, и когда мы рассматриваем разные категории, бизнес решил, что хотел бы показать стиль шаблона разных элементов для каждой другой категории.

Основная причина этого - избежать неприятного хакерского решения и найти хороший чистый метод.

Надеюсь, я предоставил достаточно информации, дайте мне знать, если вам нужно больше.

4b9b3361

Ответ 1

Просто указать DataTemplates в Resources с соответствующим DataType, например

<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

(Обратите внимание, что DataTemplate.DataType также может использоваться для неявного шаблона данных XML (см. документы), тип свойства по этой причине not System.Type, поэтому в отличие от Style.TargetType вам нужно использовать x:Type для ссылки на CLR-тип. Если вы просто вводите строку, она не будет преобразована в тип.)

Вы также можете просмотреть CompositeCollections, чтобы получить чистые объединенные списки разных типов.


Примеры данных, которые я использовал:

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;

Ответ 2

Один из вариантов заключается в создании DataTemplateSelector в вашем коде:

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;
    }
}

Это будет объявлено в вашем XAML как ресурс

        <ResourceDictionary>
            <local:QueueDisplayDataTemplateSelector x:Key="QueueDisplayDataTemplateSelector" />

И тогда вы назначили это вам в список:

    <ListBox ItemsSource="{Binding ListBoxContents}" 
             ItemTemplateSelector="{StaticResource QueueDisplayDataTemplateSelector}"
             >