WPF:组合框内的 TreeView

问题描述 投票:0回答:8

我试图将 TreeView 放入 WPF 中的 ComboBox 中,以便当组合框被删除时,用户获得的不是平面列表,而是分层列表,并且他们选择的任何节点都将成为 ComboBox 的选定值。

我已经搜索了很多如何实现这一点,但我能找到的最好的只是一些潜在的解决方案,因为我对 WPF 非常陌生,所以我无法工作。

我对 WPF 和数据绑定有足够的了解,我可以将数据放入树视图中,甚至可以将树视图放入组合框内,但是我所完成的工作根本无法正常运行。我附上了一张屏幕截图来说明我的意思。在屏幕截图中,组合框处于“打开”状态,因此底部的树视图是我可以选择节点的位置,而“顶部”的树视图则绘制在组合框的顶部,我希望在其中显示所选节点的文本/值在要显示的树中。

基本上我不知道该怎么做是如何让树视图当前选定的节点将其值返回到组合框,然后将其用作其选定值?

这是我当前使用的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>

截图:TreeView

wpf combobox treeview
8个回答
16
投票

对于那些仍然需要此控件的人,我已经实现了我的 Silverlight 控件 的 WPF 版本。它仅适用于视图模型,并要求这些视图模型实现特殊的接口,但除此之外它并不难使用。

在 WPF 中,它看起来像这样:

WPF Combobox with TreeView

您可以从这里下载源代码和示例应用程序:WpfComboboxTreeview.zip


9
投票

我也有同样的问题。

在组合框中实现树视图行为的最简单方法是创建一个 TextBox 并将其样式化为看起来像组合框。在其旁边添加图像。诀窍是将树视图放在弹出控件中。然后,当用户单击文本框或您选择的下拉图像时,弹出窗口将直接显示在文本框下方。

然后,当选择树视图项目时,关闭弹出窗口并将现在所选的文本放置在文本框中。

这是一个未风格化的示例:

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>

这是背后的代码:

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;
      }
   }
}

1
投票

您可以使用树视图上的事件处理程序来设置组合框上的 SelectedItem。

为了做到这一点,您需要像这样设置树视图的标签属性:

<TreeView Tag="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}"  MouseDoubleClick="treeview_MouseDoubleClick" ItemsSource="{Binding Children}" x:Name="TheTree">

现在在 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)
        {

        }
    }

您还需要重写组合框项目的选择方式,否则一旦您单击它,整个 TreeView 就会被选择。


1
投票

这个问题其实和那个问题密切相关

因此您可能会发现此实现很有帮助。这是一个内部带有复选框的组合框,但您可以了解如何将框中的文本与弹出内容与树分离。

它还演示了这样的想法:

IsSelected
属性应该位于模型实体上,然后通过模型将其绑定回复选框
Text
属性。换句话说,您在折叠的组合框中显示的内容可能与内容完全无关...好吧,也许不完全相关,但是在我的应用程序中,当用户选择该组合中的多个复选框时,我可以在顶部文本框中显示逗号分隔的内容,或者我可以显示“选择了几个选项”,或者其他什么。

HTH=)


1
投票

这是一个古老的话题,但它对某人可能有用。

尝试用组合框做类似的事情,我尝试使用弹出窗口,它正在工作。 要将其变成一个不错的功能,需要进行大量调整。

<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>


0
投票

我认为你可以 foreach treeViewItems 然后添加到组合 1by1 中。

并在每个树视图项展开事件中,将其子项附加到组合框中。

但是,将可展开项目的高度设置为看起来像在一行中,例如 Height = 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);
}
// ======================================================

0
投票

您遇到两个问题。第一个是当您选择唯一的 ComboBoxItem(整个 TreeView)时,这就是返回到 ComboBox 的基本 ToggleButton 的 ContentPresenter 中的内容。简单地使您的 ComboBox IsEditable 将阻止整个 TreeView 放入 ComboBox 的内容中,但它仍然不会选择您在 TreeView 中选择的项目。您必须使用 TreeView 中的 SelectedItemChanged 事件来捕获所选项目,然后将其转换为“SelectedItem”。选择该项目并将其传递到 ComboBox 后,将 IsDropDownOpen 设置为 false。


0
投票

这是@VortexWolf 的解决方案(从互联网档案中恢复),但不依赖于特定的视图模型

sample

© www.soinside.com 2019 - 2024. All rights reserved.