WPF:ComboBox 内的 TreeView
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/722700/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
WPF: TreeView inside a ComboBox
提问by
I'm trying to put a TreeView inside a ComboBox in WPF so that when the combo box is dropped, instead of a flat list the user gets a hierarchical list and whatever node they select becomes the selected value of the ComboBox.
我试图将 TreeView 放在 WPF 中的 ComboBox 中,以便当组合框被删除时,而不是平面列表,用户将获得一个分层列表,并且他们选择的任何节点都成为 ComboBox 的选定值。
I've searched quite a bit for how to accomplish this but the best I could find was only peices of potential soltuions that, because I'm ridiculously new to WPF, I couldn't make work.
我已经搜索了很多如何实现这一点,但我能找到的最好的只是一些潜在的解决方案,因为我对 WPF 非常陌生,所以我无法工作。
I have enough knowledge of WPF and databinding that I can get my data into the treeview and I can even get the treeview inside of the combo box, however what I've been able to accomplish doesn't behave properly at all. I've attached a screenshot to show what I mean. In the screenshot the combo box is "open", so the treeview on the bottom is where I can select a node and the treeview "on top" is being drawn on top of the combobox where I want the text/value of the selected node in the tree to be displayed.
我对 WPF 和数据绑定有足够的了解,可以将我的数据放入树视图中,甚至可以在组合框内获取树视图,但是我能够完成的操作根本不正确。我附上了一个截图来说明我的意思。在屏幕截图中,组合框是“打开的”,所以底部的树视图是我可以选择一个节点的地方,而“顶部”的树视图被绘制在组合框的顶部,我想要所选节点的文本/值在要显示的树中。
Basically what I don't know how to do is how do I get the treeview's currrently selected node to return its value back up to the combobox which then uses it as its selected value?
基本上我不知道该怎么做是如何让树视图当前选择的节点将其值返回到组合框,然后组合框将其用作其选定值?
Here is the xaml code I'm currently using:
这是我目前使用的 xaml 代码:
<ComboBox Grid.Row="0" Grid.Column="1" VerticalAlignment="Top">
<ComboBoxItem>
<TreeView ItemsSource="{Binding Children}" x:Name="TheTree">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type Core:LookupGroupItem}" ItemsSource="{Binding Children}">
<TextBlock Text="{Binding Path=Display}"/>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
</ComboBoxItem>
</ComboBox>
Screenshot:
截屏:
回答by vortexwolf
For those who still need this control, I've implemented a WPF version of my Silverlight control. It works only with view models and requires these view models to implement a special interface, but apart of this it's not difficult to use.
对于那些仍然需要这个控件的人,我已经实现了我的Silverlight 控件的 WPF 版本。它只适用于视图模型并且需要这些视图模型来实现一个特殊的接口,但除此之外它并不难使用。
In WPF it looks like this:
在 WPF 中,它看起来像这样:
You can download source code and sample application from here: WpfComboboxTreeview.zip
您可以从这里下载源代码和示例应用程序:WpfComboboxTreeview.zip
回答by Josh
I had the same issue.
我遇到过同样的问题。
The easiest way to implement the behavior of a treeview in a combobox is to create a TextBox and stylize it to look like a combobox. Add an image next to it. The trick is to put the treeview in a popup control. Then, when the user clicks the textbox or the dropdown image you chose, the popup is displayed directly under the textbox.
在组合框中实现树视图行为的最简单方法是创建一个 TextBox 并将其样式化以使其看起来像一个组合框。在它旁边添加一个图像。诀窍是将树视图放在弹出控件中。然后,当用户单击您选择的文本框或下拉图像时,弹出窗口将直接显示在文本框下方。
Then, when the treeview item is selected, close the popup and place the text of the selected now in the textbox.
然后,当树视图项被选中时,关闭弹出窗口并将选中的文本放在文本框中。
Here's an unstylized example:
这是一个非风格化的例子:
XAML:
XAML:
<Window x:Class="ComboBoxTreeView.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" MouseEnter="Window_MouseEnter">
<Grid Margin="15">
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBox Grid.Row="0" x:Name="header" Width="300" Height="30" PreviewMouseDown="header_PreviewMouseDown" HorizontalAlignment="Left" />
<Popup Grid.Row="1" x:Name="PopupTest" AllowsTransparency="True" IsOpen="False">
<TreeView x:Name="Tree1" Initialized="Tree1_Initialized" SelectedItemChanged="Tree1_SelectedItemChanged">
<TreeViewItem Header="Test1" x:Name="Tree1Item1">
<TreeViewItem Header="1test1" />
<TreeViewItem Header="2test2" />
</TreeViewItem>
<TreeViewItem Header="Test2" />
</TreeView>
</Popup>
</Grid>
</Window>
And here is the Code behind:
这是背后的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace ComboBoxTreeView
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_MouseEnter(object sender, MouseEventArgs e)
{
}
private void Tree1_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
var trv = sender as TreeView;
var trvItem = trv.SelectedItem as TreeViewItem;
if (trvItem.Items.Count != 0) return;
header.Text = trvItem.Header.ToString();
PopupTest.IsOpen = false;
}
private void Tree1_Initialized(object sender, EventArgs e)
{
var trv = sender as TreeView;
var trvItem = new TreeViewItem() { Header="Initialized item"};
var trvItemSel = trv.Items[1] as TreeViewItem;
trvItemSel.Items.Add(trvItem);
}
private void header_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
PopupTest.Placement = System.Windows.Controls.Primitives.PlacementMode.RelativePoint;
PopupTest.VerticalOffset = header.Height;
PopupTest.StaysOpen = true;
PopupTest.Height = Tree1.Height;
PopupTest.Width = header.Width;
PopupTest.IsOpen = true;
}
}
}
回答by Kelly
You might be able to use an event handler on the tree view to set the SelectedItem on the comboBox.
您可以在树视图上使用事件处理程序来设置组合框上的 SelectedItem。
In order to do this you would need to set the Tag porperty of the tree view like so:
为此,您需要像这样设置树视图的标签属性:
<TreeView Tag="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}" MouseDoubleClick="treeview_MouseDoubleClick" ItemsSource="{Binding Children}" x:Name="TheTree">
Now in the DoubleClick event you can get at the ComboBox:
现在在 DoubleClick 事件中,您可以获得 ComboBox:
private void treeview_MouseDoubleClick(object sender, RoutedEventArgs e)
{
try
{
TreeView tv = sender as TreeView;
if(tv == null)
return;
var cB = tv.Tag as ComboBox;
cB.SelectedItem = tv.SelectedItem;
}
catch (Exception e)
{
}
}
You will also need to override the way the comboBox Item is selecte, otherwise the whole TreeView will be selected as soon as you click on it.
您还需要覆盖选择组合框项的方式,否则只要您点击它,整个 TreeView 就会被选中。
回答by Max Galkin
This question is actually closely related to that one
这个问题其实和那个密切相关
So you would probably find this implementationhelpful. This is a combobox with checkboxes inside, but you can get the idea on how to decouple the text in the box from the popup content with your tree.
所以你可能会发现这个实现很有帮助。这是一个内部带有复选框的组合框,但您可以了解如何将框中的文本与带有树的弹出内容分离。
It also demonstrates the idea that the IsSelected
property should be on your model entities and then it is bound back to the checkbox Text
property through the model. In other words, what you show in the combobox collapsed might be completely unrelated to the content... Well, maybe not completely, but in my app when a user selects several checkboxes in that combo I can show comma-separated in the top textbox, or I can show "Several options selected", or whatever.
它还演示了该IsSelected
属性应该在您的模型实体上,然后Text
通过模型将其绑定回复选框属性的想法。换句话说,您在折叠的组合框中显示的内容可能与内容完全无关......好吧,也许不完全,但在我的应用程序中,当用户选择该组合中的多个复选框时,我可以在顶部文本框中显示逗号分隔,或者我可以显示“选择了几个选项”,或者其他什么。
HTH =)
HTH =)
回答by user3189858
It's an old topic but it can be useful to somebody.
这是一个古老的话题,但它可能对某些人有用。
Trying to do something similar with a combobox, I tried to use popup instead and it's working. To turn it into a nice feature it needs a lot of tweaking.
尝试用组合框做类似的事情,我尝试使用弹出窗口,它正在工作。要将它变成一个不错的功能,它需要进行大量调整。
<Expander Header="TestCS">
<Popup IsOpen="{Binding IsExpanded, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Expander}}}">
<TreeView ItemsSource="{Binding CSTree.CSChildren}">
<TreeView.Resources>
<HierarchicalDataTemplate ItemsSource="{Binding CSChildren}" DataType="{x:Type ViewModel:ObservableCS}">
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="16" Text="{Binding CSName}"></TextBlock>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
</Popup>
</Expander>
回答by Oh my dog
I think you can foreach treeViewItems then add into combo 1by1.
我认为您可以 foreach treeViewItems 然后添加到组合 1by1。
and in each treeviewitem expand event, append its children into combobox.
并在每个 treeviewitem expand 事件中,将其子项附加到组合框中。
however, set expandable item's height to looks like in one row, such as Height = 18d.
但是,将可扩展项的高度设置为看起来像在一行中,例如高度 = 18d。
// == Append Item into combobox =================
TreeViewItem root = new TreeViewItem();
root.Header = "item 1";
TreeViewItem t1 = new TreeViewItem();
t1.Header = "Expanding...";
root.Items.Add(t1);
// ==============================================
// == root expandind event ==============================
root.Height = 18.00d;
TreeViewItem[] items = GetRootChildren(root.Tag);
foreach(TreeViewItem item in items)
{
combox1.Items.Add(item);
}
// ======================================================