如何混合数据绑定和静态水平在树视图?
-
06-07-2019 - |
题
我有一个采集的 数据库 对象,每个含有收藏的 架构 目的和 用户 对象。我要绑到树视图,但加入附加的静态水平的层次结构,使得树视图看起来或多或少是这样的:
<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>
我能够得到相当接近,我希望通过使用以下模板:
<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>
然后在代码,我结合这样的:
TreeViewItem treeViewItem = new TreeViewItem();
treeViewItem.Header = "All the databases:";
treeViewItem.ItemsSource = server.Databases;
treeView.Items.Add(treeViewItem);
得到的树视图看起来像我想要的,但它不能选择一个特定的模式或用户。显然WPF看到整个子树植根于在一个数据库节点作为一个单一的项目,它只选择了整个事情。我需要能够选择一个特定的模式、用户或数据库。我怎么设置的模板和绑定,以便它的工作方式,我需要什么?
解决方案
哦,天哪这是一个非常令人沮丧的任务。我已经试图这样做自己很多倍。我有一个非常类似的要求在那里我有东西就像一个顾客类的两个地点收集和订单的收集。我想地点和订单"文件夹"中树图。因为你发现,所有的树视图的实例说明如何结合到自引用的类型几乎是无用的。
第一,我使出手建立一个树FolderItemNode和ItemNode对象,我会产生的模型,但这击败的目的结合,因为它不会回应基本集合的变化。
然后我想出了一个办法,似乎运作得很好。
- 在上述所描述的目的模式,我创造了类LocationCollection和OrderCollection.他们两个继承ObservableCollection和复盖ToString()返回"地点"和"订单"。
- 我创建了一个MultiCollectionConverter类实现IMultiValueConverter
- 我创建了一个FolderNode类的名称和项目的财产。这是符的对象,就表示你的"文件夹"中树图。
- 定义hierarchicaldatatemplate的使用MultiBinding任何地方,你要集团多次儿童集到文件夹。
所得XAML类似于代码下面,你可以 抓住一个邮编文件,该文件有所有类和XAML在工作实例.
<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不太适合你想要的东西:它希望所有的子节点都是相同的类型。由于您的数据库节点具有Collection <Schemas
<!> gt;类型的节点;和类型Collection <Users
<!> gt;您不能使用HierarchicalDataTemplate。更好的方法是使用包含ListBox的嵌套扩展器。
下面的代码可以实现您的想法,同时尽可能接近原始意图:
<Window x:Class="TreeViewSelection.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:smo="clr-namespace:TreeViewSelection"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<Style TargetType="ListBox">
<Setter Property="BorderThickness" Value="0"/>
</Style>
<DataTemplate DataType="{x:Type smo:Database}">
<TreeViewItem Header="{Binding Name}">
<TreeViewItem Header="Schemas">
<ListBox ItemsSource="{Binding Schemas}"/>
</TreeViewItem>
<TreeViewItem Header="Users">
<ListBox ItemsSource="{Binding Users}"/>
</TreeViewItem>
</TreeViewItem>
</DataTemplate>
<DataTemplate DataType="{x:Type smo:User}" >
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type smo:Schema}">
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</Window.Resources>
<StackPanel>
<TreeViewItem ItemsSource="{Binding DataBases}" Header="All DataBases">
</TreeViewItem>
</StackPanel>
</Window>
using System.Collections.ObjectModel;
using System.Windows;
namespace TreeViewSelection
{
public partial class Window1 : Window
{
public ObservableCollection<Database> DataBases { get; set; }
public Window1()
{
InitializeComponent();
DataBases = new ObservableCollection<Database>
{
new Database("Db1"),
new Database("Db2")
};
DataContext = this;
}
}
public class Database:DependencyObject
{
public string Name { get; set; }
public ObservableCollection<Schema> Schemas { get; set; }
public ObservableCollection<User> Users { get; set; }
public Database(string name)
{
Name = name;
Schemas=new ObservableCollection<Schema>
{
new Schema("Schema1"),
new Schema("Schema2")
};
Users=new ObservableCollection<User>
{
new User("User1"),
new User("User2")
};
}
}
public class Schema:DependencyObject
{
public string Name { get; set; }
public Schema(string name)
{
Name = name;
}
}
public class User:DependencyObject
{
public string Name { get; set; }
public User(string name)
{
Name = name;
}
}
}
您需要在绑定中使用数据库中的数据填充您正在使用的属性。目前,您正在使用新的TreeViewItem
,并将其用作数据源,因此您所说的将所有内容视为单个节点都是有意义的,因为您已将其放在单个节点中。
您需要加载数据库数据并将其作为绑定项附加到您在WPF模板中使用的属性。
这是对Josh使用SMO的解决方案的修改(我原来的问题陈述):
<Window.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:FolderNode}" ItemsSource="{Binding Items}">
<TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type smo:Database}">
<HierarchicalDataTemplate.ItemsSource>
<MultiBinding>
<MultiBinding.Converter>
<local:MultiCollectionConverter />
</MultiBinding.Converter>
<Binding Path="Schemas" />
<Binding Path="Users" />
</MultiBinding>
</HierarchicalDataTemplate.ItemsSource>
<TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type smo:User}" >
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type smo:Schema}">
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</Window.Resources>
和修改过的转换器:
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
FolderNode[] result = new FolderNode[values.Length];
for (int i = 0; i < values.Length; ++i)
{
result[i].Items = (IEnumerable)values[i];
result[i].Name = values[i] is UserCollection ? "Users" : "Schemas";
}
return result;
}
归因注意:从 OP的最终解决方案复制的内容,以< a href =“https://stackoverflow.com/revisions/1815056/3”>编辑问题,而不是作为答案