WPF TreeView 分层数据模板 - 绑定具有不同子集合的对象

3

我正在尝试使用数据模板将一个集合绑定到WPF TreeView控件。该集合中的每个项目(人)还包含两个不同类型(汽车、书籍)的集合(Cars、Books)。

以下是涉及到的对象列表,为了节省空间做了简化。

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
这有点复杂,因为你的树有两个不同的子集合。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类中定义一个属性并定义绑定:

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

这应该能指引您朝正确的方向前进,但不要将我的代码视为可编译的 :-)


3
CompositeCollection是一个不错的选择,但你不能将子集合绑定到DataContext,因为它不是一个Freezable。你只能将它们绑定到资源中。(关于这一点,请参见此问题)。这使得在HierarchicalDataTemplate中使用它有些困难,因为其中一个ItemsSource需要绑定到当前上下文中的属性才能发挥作用。
如果你不需要对集合进行更改通知,你可以在你的视图模型中轻松地实现一个属性,例如:
public IEnumerable<object> Items
{
   get { return Books.Concat(Cars); }
}

如果您需要对集合进行更改通知,那就不是很简单了。

由于我的实体是基于 XSD 的,所以我无法真正创建 CompositeCollection。但是从 XSD 生成的代码是部分的,因此我可以插入 IEnumerable! - Kolky

1
你需要一个 DataTemplate,否则 WPF 不知道如何显示你的对象。

1
你能帮我设计一下模板吗? - Jama

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接