Подтвердить что ты не робот

WPF: TreeView внутри ComboBox

Я пытаюсь поместить TreeView внутри ComboBox в WPF, так что, когда поле со списком удалено, вместо плоского списка пользователь получает иерархический список, а любой node, который они выбирают, становится выбранным значением ComboBox.

Я довольно много искал, как это сделать, но лучшее, что я мог найти, это только пэки потенциальных решений, потому что я смехотворно новичок в WPF, я не мог работать.

У меня достаточно знаний WPF и привязки данных, что я могу получить свои данные в древовидной структуре, и я даже могу получить древовидную структуру внутри поля со списком, однако то, что я смог выполнить, не ведет себя должным образом. Я добавил скриншот, чтобы показать, что я имею в виду. На скриншоте поле со списком "открыто", поэтому древовидное представление внизу - это то, где я могу выбрать node, а древовидное представление "сверху" нарисовано поверх комбобокса, где я хочу, чтобы текст/значение выбранный node в отображаемом дереве.

В основном то, что я не знаю, как это сделать, - как мне получить выбранное древовидное дерево node, чтобы вернуть его значение обратно в combobox, который затем использует его как выбранное значение?

Вот код 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

4b9b3361

Ответ 1

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

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

WPF Combobox with TreeView

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

Ответ 2

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

Самый простой способ реализовать поведение treeview в combobox - создать TextBox и стилизовать его, чтобы он выглядел как combobox. Добавьте изображение рядом с ним. Трюк состоит в том, чтобы поместить древовидную структуру во всплывающее управление. Затем, когда пользователь нажимает текстовое поле или выпадающее изображение, которое вы выбрали, всплывающее окно отображается непосредственно под текстовым полем.

Затем, когда выбран элемент treeview, закройте всплывающее окно и поместите текст выделенного теперь в текстовое поле.

Здесь представлен неэтилированный пример:

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

Ответ 3

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

Чтобы сделать это, вам нужно установить тактировку 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 будет выбран, как только вы нажмете на него.

Ответ 4

Этот вопрос фактически тесно связан с тем, что один

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

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

HTH =)

Ответ 5

Это старая тема, но она может быть полезной для кого-то.

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

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

Ответ 6

Я думаю, вы можете foreach treeViewItems затем добавить в combo 1by1.

и в каждом событии развернуть treeviewitem добавьте его дочерние элементы в combobox.

однако, установите расширяемую высоту элемента, чтобы выглядеть как в одной строке, например 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);
}
// ======================================================