WPF: TreeView внутри ComboBox - PullRequest
16 голосов
/ 06 апреля 2009

Я пытаюсь поместить TreeView внутри ComboBox в WPF, чтобы при удалении комбинированного окна вместо плоского списка пользователь получал иерархический список, и любой выбранный им узел становился выбранным значением 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

Ответы [ 6 ]

16 голосов
/ 03 декабря 2013

Для тех, кому все еще нужен этот элемент управления, я реализовал WPF-версию моего элемента управления Silverlight . Он работает только с моделями представлений и требует, чтобы эти модели представлений реализовывали специальный интерфейс, но кроме этого его не сложно использовать.

В WPF это выглядит так:

WPF Combobox with TreeView

Вы можете скачать исходный код и пример приложения отсюда: WpfComboboxTreeview.zip

7 голосов
/ 08 июня 2011

У меня была такая же проблема.

Самый простой способ реализовать поведение древовидной структуры в комбинированном ящике - создать 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 голос
/ 04 марта 2014

Это старая тема, но она может кому-нибудь пригодиться.

Пытаясь сделать что-то подобное с помощью комбинированного списка, я попытался использовать всплывающее окно, и оно работает. Чтобы превратить его в приятную функцию, нужно много доработать.

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

1 голос
/ 21 декабря 2009

Этот вопрос на самом деле тесно связан с этим

Таким образом, вы, вероятно, найдете эту реализацию полезной. Это комбинированный список с флажками внутри, но вы можете получить представление о том, как отделить текст в поле от всплывающего содержимого с вашим деревом.

Это также демонстрирует идею о том, что свойство IsSelected должно присутствовать в объектах модели, а затем оно связывается со свойством checkbox Text через модель. Другими словами, то, что вы показываете в свернутом поле со списком, может быть совершенно не связано с контентом ... Ну, может быть, не полностью, но в моем приложении, когда пользователь выбирает несколько флажков в этом комбо, я могу показывать разделенные запятыми в верхнем текстовом поле. или я могу показать «Выбрано несколько опций», или что угодно.

HTH =)

1 голос
/ 07 апреля 2009

Возможно, вы сможете использовать обработчик событий в древовидном представлении, чтобы установить SelectedItem в поле со списком.

Для того, чтобы сделать это, вам нужно установить тег Tag для дерева, например, так:

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

        }
    }

Вам также нужно будет изменить способ выбора элемента comboBox, иначе весь TreeView будет выбран, как только вы нажмете на него.

0 голосов
/ 15 апреля 2013

Я думаю, что вы можете перейти к treeViewItems, а затем добавить в комбо 1by1.

и в каждом событии дерева просмотра добавьте его дочерние элементы в выпадающий список.

однако, установите высоту раскрываемого элемента так, чтобы она выглядела в одном ряду, например, Высота = 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);
}
// ======================================================
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...