WPF TreeView HierarchicalDataTemplate - привязка к объекту с различными дочерними коллекциями - PullRequest
3 голосов
/ 19 февраля 2010

Я пытаюсь привязать коллекцию к элементу управления wpf TreeView, используя шаблоны данных.Каждый элемент (Персона) в коллекции также содержит две разные коллекции (Автомобили, Книги) типа car и book.

Вот упрощенный список объектов, используемых для экономии места.

public class Person
{
  public string Name
  public List<Book> Books;
  public List<Car> Cars;
}

public class Book
{
  public string Title
  public string Author
}

public class Car
{
  public string Manufacturer;
  public string Model;
}

Вот как я связываюсь

    public MainWindow()
    {
        InitializeComponent();

        this.treeView1.ItemsSource = this.PersonList();
    }

    public List<Person> PersonList()
    {
        List<Person> list = new List<Person>();


        Book eco = new Book { Title = "Economics 101", Author = "Adam Smith"};
        Book design = new Book { Title = "Web Design", Author = "Robins" };

        Car corola = new Car { Manufacturer = "Toyota", Model = "2005 Corola"};
        Car ford = new Car { Manufacturer = "Ford", Model = "2008 Focus"};

        Person john = new Person { Name = "John", Books = new ObservableCollection<Book> { eco, design }, Cars = new ObservableCollection<Car> { corola } };

        Person smith = new Person { Name = "Smith", Books = new ObservableCollection<Book> { eco, design }, Cars = new ObservableCollection<Car> { ford } };

        list.AddRange(new[] {john, smith });
        return list;
    }

Вот код Xaml

<Grid>
    <TreeView  Name="treeView1">
    </TreeView>
</Grid>

Я смотрю, чтобы дерево выглядело так:

>John
  >Books
    Economics 101 : Adam Smith
    Web Design    : Robins
  >Cars
    Totota : 2005 Corola
>Smith
  >Books
    Economics 101 : Adam Smith
    Web Design    : Robins
  >Cars
    Ford: 2008 Focus

этот знак > используется для отображения папки дерева и не должен учитываться в шаблоне.

Ответы [ 3 ]

7 голосов
/ 19 февраля 2010

Это немного сложно, поскольку у вашего дерева есть две разные дочерние коллекции. WPF не поддерживает сценарий с несколькими определениями ItemsSource. Поэтому вам необходимо объединить эти коллекции в CompositeCollection . Сопоставление типов составных элементов (например, Car, Book) будет выполнено автоматически.

В XAML вам нужно определить так называемые HierarchicalDataTemplates , которые соответствуют вашим определениям типов. Если local указывает на пространство имен, где определены Book, Car и Person, упрощенный HierarchicalDataTemplates может выглядеть следующим образом:

 <HierarchicalDataTemplate DataType="{x:Type local:Person}" 
                              ItemsSource="{Binding CompositeChildren}">
        <TextBlock Text="{Binding Path=Name}" />
    </HierarchicalDataTemplate>

    <HierarchicalDataTemplate DataType="{x:Type local:Book}">
        <TextBlock Text="{Binding Path=Title}" />
        <!-- ... -->
    </HierarchicalDataTemplate>

    <HierarchicalDataTemplate DataType="{x:Type local:Car}">
        <TextBlock Text="{Binding Path=Model}" />
        <!-- ... -->
    </HierarchicalDataTemplate>

Тогда вам нужно подключить свою коллекцию к дереву управления. Есть несколько возможностей сделать это, проще всего было бы определить свойство в вашем классе Window и определить Binding:

<TreeView Items={Binding ElementName=myWindow, Path=Persons}/>

Это должно указать вам правильное направление, но не принимайте мой код как готовый к компиляции: -)

3 голосов
/ 20 февраля 2010

CompositeCollection - хороший ответ, за исключением того, что вы не можете привязать дочерние коллекции к DataContext, потому что это не Freezable.Вы можете привязать их только к ресурсам.(Подробнее см. в этом вопросе .) Это затрудняет использование в HierarchicalDataTemplate, так как ItemsSource в одном необходимо привязать к свойству в текущем контексте, чтобы быть полезным.

Если вам не нужно уведомление об изменениях в коллекциях, вы можете легко реализовать свойство в своей модели представления, например:

public IEnumerable<object> Items
{
   get { return Books.Concat(Cars); }
}

Если вам нужно уведомление об изменении в коллекции,это гораздо менее тривиально.

1 голос
/ 19 февраля 2010

Вам нужен DataTemplate, иначе WPF не знает, как отобразить ваш объект.

...