WPF: TreeView dentro de un ComboBox
(6)
Creo que puedes permitir cada treeViewItems y luego agregarlo al combo 1by1.
y en cada evento de expansión de vista de árbol, agregue a sus hijos en el cuadro combinado.
sin embargo, establezca la altura del elemento expandible para que se vea como en una fila, como Altura = 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);
}
// ======================================================
Estoy tratando de colocar un TreeView dentro de un ComboBox en WPF para que cuando se descarte el cuadro combinado, en lugar de una lista plana, el usuario obtenga una lista jerárquica y cualquier nodo que seleccione se convierta en el valor seleccionado del ComboBox.
He buscado bastante para saber cómo lograr esto, pero lo mejor que pude encontrar fueron solo partes de soluciones potenciales que, como soy ridículamente nuevo en WPF, no pude hacer funcionar.
Tengo suficiente conocimiento de WPF y del enlace de datos que puedo hacer que mis datos ingresen a la vista de árbol e incluso puedo obtener la vista de árbol dentro del cuadro combinado, sin embargo, lo que he podido lograr no se comporta correctamente. He adjuntado una captura de pantalla para mostrar lo que quiero decir. En la captura de pantalla, el cuadro combinado está "abierto", por lo que la vista de árbol en la parte inferior es donde puedo seleccionar un nodo y la vista de "arriba" se está dibujando en la parte superior del cuadro combinado donde quiero el texto / valor del nodo seleccionado en el árbol que se mostrará.
Básicamente, lo que no sé cómo hacer es cómo hacer que el nodo seleccionado actualmente de la vista de árbol regrese su valor al cuadro combinado que luego lo usa como su valor seleccionado.
Aquí está el código xaml que estoy usando actualmente:
<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>
Captura de pantalla:
Es posible que pueda usar un controlador de eventos en la vista de árbol para establecer SelectedItem en el comboBox.
Para hacer esto, deberías establecer la porte de la etiqueta de la vista de árbol de la siguiente manera:
<TreeView Tag="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}" MouseDoubleClick="treeview_MouseDoubleClick" ItemsSource="{Binding Children}" x:Name="TheTree">
Ahora en el evento de DoubleClick puede obtener en el 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)
{
}
}
También deberá anular la forma en que se selecciona el elemento del comboBox, de lo contrario, se seleccionará todo el TreeView tan pronto como lo haga clic en él.
Es un tema viejo pero puede ser útil para alguien.
Tratando de hacer algo similar con un combobox, intenté usar la ventana emergente y está funcionando. Para convertirlo en una buena característica, necesita muchos ajustes.
<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>
Esta pregunta está realmente relacionada con esa
Así que probablemente encuentre útil esta implementación . Este es un cuadro combinado con casillas de verificación dentro, pero puede tener la idea de cómo desacoplar el texto en el cuadro del contenido emergente con su árbol.
También demuestra la idea de que la propiedad IsSelected
debe estar en las entidades modelo y luego se vincula de nuevo a la propiedad Text
la casilla de verificación a través del modelo. En otras palabras, lo que se muestra en el cuadro combinado colapsado puede no estar relacionado con el contenido ... Bueno, tal vez no completamente, pero en mi aplicación cuando un usuario selecciona varias casillas de verificación en esa combinación, puedo mostrar separadas por comas en el cuadro de texto superior , o puedo mostrar "Varias opciones seleccionadas", o lo que sea.
HTH =)
Para aquellos que todavía necesitan este control, he implementado una versión WPF de mi vortexwolf.wordpress.com/2011/04/29/… . Funciona solo con modelos de vista y requiere que estos modelos de vista implementen una interfaz especial, pero aparte de esto no es difícil de usar.
En WPF se ve así:
Puede descargar el código fuente y la aplicación de muestra desde aquí: WpfComboboxTreeview.zip
Tuve el mismo problema.
La forma más sencilla de implementar el comportamiento de una vista de árbol en un cuadro combinado es crear un Cuadro de texto y estilizarlo para que se vea como un cuadro combinado. Añade una imagen junto a ella. El truco es poner la vista de árbol en un control emergente. Luego, cuando el usuario hace clic en el cuadro de texto o en la imagen desplegable que eligió, la ventana emergente se muestra directamente debajo del cuadro de texto.
Luego, cuando se selecciona el elemento de vista de árbol, cierre la ventana emergente y coloque el texto del seleccionado ahora en el cuadro de texto.
Aquí hay un ejemplo sin estilizar:
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>
Y aquí está el Código detrás:
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;
}
}
}