WPF Treeview Databinding Hierarchal Data со смешанными типами - PullRequest
33 голосов
/ 09 сентября 2010

У меня немного сложная ситуация с WPF Treeview Binding. Я провел последние 2 дня, пробуя Google, и this - закрытый вариант, который я придумал, но это не решает проблему.

Вот ситуация:

У меня есть объект, который выглядит так:

public class Category
{
  public string Name { get; set; }
  public List<Category> Categories { get; set; }
  public List<Product> Products { get; set; }
}

public class Product
{
  public string Name { get; set;
}

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

Реальная конструкция объекта может выглядеть примерно так:

Category - Pharmacy
  |-Product - Aspirin
  |-Product - Tylenol
  |-Category - Tooth Paste
  |  |-Product - Crest
  |  |-Product - Colgate
  |-Category - Paper Products
   |-Category - Toilet Paper
   |  |-Product - NoName
   |  |-Product - Charmin
   |-Category - Facial Tissue
      |-Product - Kleenex
Category - Household
  |-Product - Pinesol Cleaner
  |-Product - Garbage Bags

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

Пока что мой XAML Treeview выглядит так:

  <TreeView x:Name="CategoryList" Margin="8" Grid.Row="2" Grid.RowSpan="2" ItemsSource="{Binding Path=Categories}">
            <TreeView.Resources>
                <HierarchicalDataTemplate DataType="{x:Type src:Category}" ItemsSource="{Binding Products}">
                    <StackPanel>
                        <TextBlock Text="{Binding Path=Name}" />
                    </StackPanel>
                </HierarchicalDataTemplate>
                <HierarchicalDataTemplate DataType="{x:Type src:Product}">
                    <StackPanel>
                        <TextBlock Text="{Binding Path=Name}" />
                    </StackPanel>
                </HierarchicalDataTemplate>
            </TreeView.Resources>
        </TreeView>

Это прекрасно работает для основного списка категорий и каждого из его субпродуктов. Но это не идет глубже и отображает подкатегории под каждой категорией.

Есть ли способ сделать это непосредственно с помощью шаблонов, чтобы каждый элемент (категория или продукт) был выбран? Я использую шаблон MVVM и не хочу прибегать к использованию кода, но я сделаю это, если это необходимо.

1 Ответ

54 голосов
/ 09 сентября 2010

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

public class Category
{
    public string Name { get; set; }
    public List<Category> Categories { get; set; }
    public List<Product> Products { get; set; }

    public IList Children
    {
        get
        {
            return new CompositeCollection()
            {
                new CollectionContainer() { Collection = Products },
                new CollectionContainer() { Collection = Categories }
            };
        }
    }
}

(В реальном коде вы, вероятно, захотите сохранить ссылку на тот же объект коллекции, а не создаватькаждый раз новый.)

Затем в вашем HierarchicalDataTemplate используйте объединенный список в качестве ItemsSource:

<HierarchicalDataTemplate DataType="{x:Type src:Category}"
                          ItemsSource="{Binding Children}">

Элементы будут представлять собой сочетание объектов Product и Category, а WPF будетиспользуйте соответствующий DataTemplate для каждого.

...