如何在TreeView中混合数据绑定和静态级别?

Paw*_*iak 12 data-binding wpf treeview hierarchicaldatatemplate

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

<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>
Run Code Online (Sandbox Code Playgroud)

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

<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>
Run Code Online (Sandbox Code Playgroud)

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

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

生成的TreeView看起来像我想要的那样,但是不可能选择特定的模式或用户.显然,WPF将以数据库节点为根的整个子树视为单个项目,并且它只选择整个事物.我需要能够选择特定的架构,用户或数据库.如何设置模板和绑定,使其按照我需要的方式工作?

Jos*_*osh 12

哦,这是一项令人难以置信的令人沮丧的任务.我已经尝试过很多次了.我有一个非常相似的要求,我有一个类似于具有Locations集合和Orders集合的Customer类.我希望Locations和Orders在树视图中成为"文件夹".正如您所发现的,所有向您展示如何绑定到自引用类型的TreeView示例都是无用的.

首先,我使用手动构建我将在ViewModel中生成的FolderItemNode和ItemNode对象的树,但这违背了绑定的目的,因为它不会响应底层的集合更改.

然后我想出了一种似乎运作良好的方法.

  • 在上面描述的对象模型中,我创建了类LocationCollection和OrderCollection.它们都从ObservableCollection继承并覆盖ToString()以分别返回"Locations"和"Orders".
  • 我创建了一个实现IMultiValueConverter的MultiCollectionConverter类
  • 我创建了一个具有Name和Items属性的FolderNode类.这是占位符对象,它将代表树视图中的"文件夹".
  • 定义在任何想要将多个子集合分组到文件夹中的MultiBinding使用的hierarchicaldatatemplate.

生成的XAML看起来类似于下面的代码,你可以在一个工作示例中获取一个包含所有类和XAML的zip文件.

<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>
Run Code Online (Sandbox Code Playgroud)

TreeView中的文件夹

  • 您提供的工作示例是否仍然存在?我只是试图访问它,链接显示已损坏. (5认同)