【问题标题】:WPF TreeView HierarchicalDataTemplate - binding to object with different child collectionsWPF TreeView HierarchicalDataTemplate - 绑定到具有不同子集合的对象
【发布时间】:2010-02-19 19:23:45
【问题描述】:

我正在尝试使用数据模板将集合绑定到 wpf TreeView 控件。集合中的每个项目(Person)还包含 car 和 book 类型的两个不同集合(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

这个符号&gt; 用于显示树形文件夹,不应在模板中考虑。

【问题讨论】:

    标签: wpf treeview hierarchicaldatatemplate


    【解决方案1】:

    这有点复杂,因为您的树有两个不同的子集合。 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}/>
    

    这应该会为您指明正确的方向,但不要将我的代码视为可编译 :-)

    【讨论】:

      【解决方案2】:

      CompositeCollection 是一个很好的答案,但您不能将子集合绑定到 DataContext,因为它不是 Freezable。您只能将它们绑定到资源。 (有关更多信息,请参阅 this question。)这使得在 HierarchicalDataTemplate 中使用有点困难,因为 ItemsSource 需要绑定到当前上下文中的属性才能有用。

      如果您不需要关于集合的更改通知,您可以轻松地在视图模型中实现一个属性,例如:

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

      如果您需要关于集合的更改通知,那就不那么简单了。

      【讨论】:

      • 由于我的实体基于 ​​XSD,因此我无法真正创建 CompositeCollection。但是从 XSD 生成的代码是部分的,所以我可以插入一个 IEnumerable!
      【解决方案3】:

      您需要DataTemplate,否则 WPF 不知道如何显示您的对象。

      【讨论】:

      • 你能帮我做模板设计吗?
      猜你喜欢
      • 2010-12-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-10
      • 2011-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多