WPF Treeview对混合类型的层次数据进行数据库

时间:2022-09-16 16:26:46

I have a bit of a complex situation with WPF Treeview Binding. I have spent the last 2 days trying Google it, and this is the closed I came up with, but it doesn't solve the issue.

我对WPF Treeview绑定有一些复杂的情况。我花了两天的时间尝试谷歌,这是我想出来的,但这并不能解决问题。

Here is the situation:

这是这句话的语境是:

I have an object that looks like 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;
}

Each Category can have a list of objects, and child categories. I have a reason for doing this that makes complete sense to me, and the app I am writing.

每个类别可以有一个对象列表和子类别。我这么做是有原因的,这对我和我正在写的应用来说是完全有意义的。

The actual object construction may look Something like this:

实际的对象结构可能是这样的:

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

Now, I am trying to databind this relationship to a treeview. I would like the TreeView to look almost identical to the above object construct.

现在,我正在尝试将这个关系绑定到treeview。我希望TreeView看起来与上面的对象构造几乎相同。

So far I have my XAML Treeview look like this:

到目前为止,我的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>

This works great for the main list of Categories, and each of it's sub products. But it doesn't go deeper and display the sub categories under each category.

这对于分类的主列表和每个子产品来说都很有用。但它并没有更深入地显示每个类别下的子类别。

Is there any way to do this directly with Templates so that each item (category or product) is selected? I am using an MVVM pattern and don't want to resort to using the code behind, but will if it is necessary.

有什么方法可以直接使用模板来实现这一点,以便选择每个条目(类别或产品)吗?我使用的是MVVM模式,并不想使用后面的代码,但是如果有必要的话。

1 个解决方案

#1


46  

Since you want the elements in the TreeView to have a list of children that consists of both Categories Products, you will want your Category ViewModel to have a collection that consists of both Categories and Products. For example, you could use a CompositeCollection to combine your existing collections:

由于您希望TreeView中的元素有一个由两个类别产品组成的子元素列表,所以您将希望您的类别视图模型有一个由两个类别和产品组成的集合。例如,您可以使用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 }
            };
        }
    }
}

(In real code, you would probably want to keep a reference to the same collection object rather than creating a new one each time.)

(在真正的代码中,您可能希望保持对同一集合对象的引用,而不是每次都创建一个新的集合对象。)

Then in your HierarchicalDataTemplate, use the combined list as the ItemsSource:

然后在您的层次化的datatemplate中,使用组合列表作为ItemsSource:

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

The items will be a mix of Product and Category objects, and WPF will use the appropriate DataTemplate for each one.

项目将是产品和类别对象的混合,WPF将为每个对象使用适当的DataTemplate。

#1


46  

Since you want the elements in the TreeView to have a list of children that consists of both Categories Products, you will want your Category ViewModel to have a collection that consists of both Categories and Products. For example, you could use a CompositeCollection to combine your existing collections:

由于您希望TreeView中的元素有一个由两个类别产品组成的子元素列表,所以您将希望您的类别视图模型有一个由两个类别和产品组成的集合。例如,您可以使用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 }
            };
        }
    }
}

(In real code, you would probably want to keep a reference to the same collection object rather than creating a new one each time.)

(在真正的代码中,您可能希望保持对同一集合对象的引用,而不是每次都创建一个新的集合对象。)

Then in your HierarchicalDataTemplate, use the combined list as the ItemsSource:

然后在您的层次化的datatemplate中,使用组合列表作为ItemsSource:

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

The items will be a mix of Product and Category objects, and WPF will use the appropriate DataTemplate for each one.

项目将是产品和类别对象的混合,WPF将为每个对象使用适当的DataTemplate。