Integración de TreeView dentro de un ComboBox

El diseño de interfaces a menudo requiere la incrustación de un control TreeView dentro de un ComboBox para optimizar el espacio. Implementar esta funcionalidad implica modificar la plantilla del ComboBox. Específicamente, se debe alterar la plantilla del ComboBoxItem y también la plantilla de elementos del TreeView.

Se define una estructura para cada elemento del TreeView. Esta incluye un pequeño cuadrado de 13x13 píxeles que simula un CheckBox mediante un Path con una marca de verificación, cuya visibilidad se controla mediante código. A continuación, se añade un TextBlock para mostrar el texto del elemento. Se utiliza un HierarchicalDataTemplate para manejar la estructura jerárquica de los datos del TreeView.

<ComboBox x:Name="comboBox" SelectionChanged="comboBox_SelectionChanged">
    <ComboBoxItem Content="{Binding Name}" Visibility="Collapsed"/>
    <ComboBoxItem x:Name="comTree" FocusVisualStyle="{x:Null}">
       <ComboBoxItem.Template>
            <ControlTemplate>
                 <TreeView Name="treeView" ItemsSource="{Binding TreeViewItems}" SelectedValuePath="DataName" DisplayMemberPath="DataName"
                                 Margin="0" SelectedItemChanged="treeView_SelectedItemChanged" BorderThickness="0">
                      <TreeView.ItemTemplate>
                          <HierarchicalDataTemplate ItemsSource="{Binding Items}">
                                   <StackPanel Orientation="Horizontal" Margin="0,1">
                                          <Grid Height="13" Width="13" VerticalAlignment="Center" Margin="2,0,0,0">
                                                <Border BorderBrush="#5c8200" BorderThickness="1"/>
                                                <Path Stroke="#5c8200" StrokeThickness="1" Data="M 2,7 5,11 11,2" Visibility="{Binding Visibility}"/>
                                          </Grid>
                                          <TextBlock Text="{Binding Name}" Margin="2,0,0,0"/>
                                   </StackPanel>
                        </HierarchicalDataTemplate>
                   </TreeView.ItemTemplate>
                </TreeView>
           </ControlTemplate>
      </ComboBoxItem.Template>
    </ComboBoxItem>
</ComboBox>

Para la gestión de datos, se requieren clases auxiliares. La clase TreeData encapsula los datos de cada nodo del TreeView, implementando la interfaz INotifyPropertyChanged para asegurar la sincronización de datos entre el modelo y la interfaz de usuario cuando estos cambian.

public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string prop)
{
  if (this.PropertyChanged != null)
  this.PropertyChanged(this, new PropertyChangedEventArgs(prop));
}

Además, se define una clase ViewModel que inicializa los datos a enlazar con la vista, siguiendo el patrón MVVM para una gestión de datos robusta. Esta clase puede cnotener propiedades y datos adicionales necesarios.

Debido a la personalización del ComboBox, se puede crear un control de usuario dedicado para encapsular las operaciones relacionadas con el ComboBox y su TreeView anidado, simplificando su uso en la ventana principal.

Un aspecto crucial es la actualización del ComboBox al seleccionar un elemento en el TreeView. Para ello, se incluye un ComboBoxItem inicialmente oculto (Visibility="Collapsed") cuyo Content se enlaza a la propiedad Name del elemento seleccionado en el TreeView. Al seleccionar un nodo, el Content de este ComboBoxItem se actualiza con el nombre del nodo seleccionado, y el SelectedIndex del ComboBox se establece en 0, haciendo visible el nombre del elemento seleccionado en el desplegable. Se adjuntan los manejadores de eventos relevantes:

private void treeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
      if (this.selectedItem != null)
      this.selectedItem.Visibility = Visibility.Collapsed;
      this.SelectedItem = e.NewValue as TreeData;
}

private void comboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
      this.comboBox.SelectedIndex = 0;
}

Se implementa una propiedad SelectedItem para gestionar el elemento actualmente seleccionado en el TreeView:

/// <summary>
/// Datos del elemento actualmente seleccionado.
/// </summary>
public TreeData SelectedItem
{
    get { return selectedItem; }
    set
       {
           selectedItem = value;
           dataModel.ViewModeName = value.Name;
           value.Visibility = Visibility.Visible;
       }
}

Etiquetas: WPF ComboBox TreeView ControlTemplate HierarchicalDataTemplate

Publicado el 6-7 17:30