如何在TreeView中混合数据绑定和静态级别? [英] How to mix databound and static levels in a 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屋!