如何在TreeView中混合数据绑定和静态级别? [英] How to mix databound and static levels in a TreeView?

查看:185
本文介绍了如何在TreeView中混合数据绑定和静态级别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一组数据库对象,每个对象包含 Schema 对象和 User 对象的集合。我想绑定到TreeView,但在层次结构中添加其他静态级别,以便生成的TreeView看起来或多或少是这样的:

I have a collection of Database objects, each containing collections of Schema objects and User objects. I want to bind them to a TreeView, but adding additional static levels in the hierarchy, so that the resulting TreeView looks more or less like this:

<TreeView>
    <TreeViewItem Header="All the databases:">
        <TreeViewItem Header="Db1">
            <TreeViewItem Header="Here's all the schemas:">
                <TreeViewItem Header="Schema1"/>
                <TreeViewItem Header="Schema2"/>
            </TreeViewItem>
            <TreeViewItem Header="Here's all the users:">
                <TreeViewItem Header="User1"/>
                <TreeViewItem Header="User2"/>
            </TreeViewItem>
        </TreeViewItem>
        <TreeViewItem Header="Db2">
            <TreeViewItem Header="Here's all the schemas:">
                <TreeViewItem Header="Schema1"/>
                <TreeViewItem Header="Schema2"/>
            </TreeViewItem>
            <TreeViewItem Header="Here's all the users:">
                <TreeViewItem Header="User1"/>
                <TreeViewItem Header="User2"/>
            </TreeViewItem>
        </TreeViewItem>
    </TreeViewItem>
</TreeView>

通过使用以下模板,我能够非常接近我想要的:

I was able to get pretty close to what I want by using the following templates:

<Window.Resources>
    <HierarchicalDataTemplate DataType="{x:Type smo:Database}">
        <TreeViewItem Header="{Binding Path=Name}">
            <TreeViewItem Header="Here's all the schemas:" ItemsSource="{Binding Path=Schemas}"/>
            <TreeViewItem Header="Here's all the users:" ItemsSource="{Binding Path=Users}"/>
        </TreeViewItem>
    </HierarchicalDataTemplate>
    <DataTemplate DataType="{x:Type smo:Schema}">
        <TextBlock Text="{Binding Path=Name}"/>
    </DataTemplate>
    <DataTemplate DataType="{x:Type smo:User}">
        <TextBlock Text="{Binding Path=Name}"/>
    </DataTemplate>
</Window.Resources>

然后在代码中我设置这样的绑定:

Then in the code I set the binding like this:

TreeViewItem treeViewItem = new TreeViewItem();
treeViewItem.Header = "All the databases:";
treeViewItem.ItemsSource = server.Databases;
treeView.Items.Add(treeViewItem);

生成的TreeView看起来像我想要的,但不可能选择特定的模式或用户。显然,WPF将整个子树视为一个数据库节点,它只会选择整个事物。我需要能够选择特定的模式,用户或数据库。如何设置模板和绑定,使其按照我需要的方式工作?

The resulting TreeView looks like I want it to, but it's not possible to select a particular schema or user. Apparently WPF sees the whole subtree rooted at a database node as a single item, and it only selects the whole thing. I need to be able to select a particular schema, user or database. How do I set the templates and bindings so that it works the way I need?

推荐答案

哦,这是一个令人难以置信的令人沮丧的任务。我已经尝试过很多次了。我有一个非常相似的要求,我有一个类似一个客户类,同时具有地点集合和订单集合。我希望位置和订单在树视图中成为文件夹。正如你所发现的,所有的TreeView示例,显示如何绑定到自引用类型几乎没有用。

Oh man this is an incredibly frustrating task. I've tried doing it myself many times. I had a very similar requirement where I've got something like a Customer class that has both a Locations collection and a Orders collection. I wanted Locations and Orders to be "folders" in the tree view. As you've discovered, all the TreeView examples that show you how to bind to self-referencing types are pretty much useless.

首先我采取手动构建一棵树我将在ViewModel中生成的FolderItemNode和ItemNode对象,但是由于它不会响应底层的集合更改,所以它击败了绑定的目的。

First I resorted to manually building a tree of FolderItemNode and ItemNode objects that I would generate in the ViewModel but this defeated the purpose of binding because it would not respond to underlying collection changes.

然后我想出了一种方法这似乎工作得很好。

Then I came up with an approach which seems to work pretty well.


  • 在上述对象模型中,我创建了ClassCollection和OrderCollection。他们都继承自ObservableCollection并重写ToString()以分别返回位置和订单。

  • 我创建一个实现IMultiValueConverter的MultiCollectionConverter类

  • 我创建了一个具有Name和Items属性的FolderNode类。这个占位符对象将在树状视图中表示您的文件夹。

  • 定义将多个子集合分组到文件夹中的任何位置使用MultiBinding的hierarchydatatemplate。

  • In the above described object model, I created classes LocationCollection and OrderCollection. They both inherit from ObservableCollection and override ToString() to return "Locations" and "Orders" respectively.
  • I create a MultiCollectionConverter class that implements IMultiValueConverter
  • I created a FolderNode class that has a Name and Items property. This is the placeholder object that will represent your "folders" in the tree view.
  • Define hierarchicaldatatemplate's that use MultiBinding anywhere that you want to group multiple child collections into folders.

生成的XAML与以下代码类似,您可以获取一个zip文件,该文件具有所有类和XAML在一个工作示例中。

The resulting XAML looks similar to the code below and you can grab a zip file which has all the classes and XAML in a working example.

<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:Local="clr-namespace:WpfApplication2"
        Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded">

    <Window.Resources>

        <!-- THIS IS YOUR FOLDER NODE -->
        <HierarchicalDataTemplate DataType="{x:Type Local:FolderNode}" ItemsSource="{Binding Items}">
            <Label FontWeight="Bold" Content="{Binding Name}" />
        </HierarchicalDataTemplate>

        <!-- THIS CUSTOMER HAS TWO FOLDERS, LOCATIONS AND ORDERS -->
        <HierarchicalDataTemplate DataType="{x:Type Local:Customer}">
            <HierarchicalDataTemplate.ItemsSource>
                <MultiBinding>
                    <MultiBinding.Converter>
                        <Local:MultiCollectionConverter />
                    </MultiBinding.Converter>
                    <Binding Path="Locations" />
                    <Binding Path="Orders" />
                </MultiBinding>
            </HierarchicalDataTemplate.ItemsSource>
            <Label Content="{Binding Name}" />
        </HierarchicalDataTemplate>

        <!-- OPTIONAL, YOU DON'T NEED SPECIFIC DATA TEMPLATES FOR THESE CLASSES -->
        <DataTemplate DataType="{x:Type Local:Location}">
            <Label Content="{Binding Title}" />
        </DataTemplate>
        <DataTemplate DataType="{x:Type Local:Order}">
            <Label Content="{Binding Title}" />
        </DataTemplate>

    </Window.Resources>

    <DockPanel>
        <TreeView Name="tree" Width="200" DockPanel.Dock="Left" />
        <Grid />
    </DockPanel>

</Window>

这篇关于如何在TreeView中混合数据绑定和静态级别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆