2010-02-11 16 views
20

Cuando expando elementos en mi vista de árbol para que sea necesario desplazarse, aparece una barra de desplazamiento. Sin embargo, no se desplaza hacia abajo para la rama de elementos recién expandida: se recortan en la parte inferior del control. Así que a medida que continúo expandiendo elementos en la parte inferior del árbol, tengo que seguir desplazándome manualmente hacia abajo para ver los nuevos hijos. ¿Alguien tiene una sugerencia sobre cómo hacer que se desplace automáticamente para mostrar los elementos recién expandidos?WPF TreeView - Cómo desplazar una rama tan expandida es visible

Respuesta

16

En TreeView, maneje el evento TreeViewItem.Expanded (puede hacerlo en el nivel TreeView debido al burbujeo de eventos). En el controlador Expanded, llame a BringIntoView en TreeViewItem que provocó el evento.

Es posible que necesite un poco de prueba y error para obtener TreeViewItem en el código de su controlador de eventos. Creo (no lo he comprobado) que el argumento del remitente para su controlador de eventos Ampliado será TreeView (ya que es allí donde está conectado el controlador de eventos) en lugar de TreeViewItem. Y e.Source o e.OriginalSource pueden ser un elemento en la plantilla de datos de TreeViewItem. Por lo tanto, es posible que necesite usar VisualTreeHelper para recorrer el árbol visual y encontrar TreeViewItem. Pero si usa el depurador para inspeccionar el remitente y los RoutedEventArgs esto debería ser trivial.

(Si puede hacer que esto funcione y desea agruparlo para que no tenga que conectar el mismo controlador de eventos a cada TreeView, debería ser fácil encapsularlo como attached behaviour que le permitirá . aplicarla de forma declarativa, incluyendo a través de un estilo)

+0

Eso realmente funciona perfectamente, pensé que habría un problema porque quiero centrarme en los elementos infantiles expandidos, no en los elementos que se expandieron, pero funciona exactamente como yo quería. Muchas gracias por la sugerencia de comportamientos adjuntos también, incluso mejor. – Jared

+0

Realmente esto funciona para mi treeview donde anulo completamente la plantilla treeviewitem, pero no funciona para mi vista de árbol más simple donde uso la plantilla treeviewitem predeterminada ... no sé por qué – Jared

2

Gracias a la respuesta itowlson de, aquí está el código de controlador de eventos ampliado que funcione para ambos de mis árboles

private static void Tree_Expanded(object sender, RoutedEventArgs e) 
{ 
    // ignore checking, assume original source is treeviewitem 
    var treeViewItem = (TreeViewItem)e.OriginalSource; 

    var count = VisualTreeHelper.GetChildrenCount(treeViewItem); 

    for (int i = count - 1; i >= 0; --i) 
    { 
     var childItem = VisualTreeHelper.GetChild(treeViewItem, i); 
     ((FrameworkElement)childItem).BringIntoView(); 
    } 

    // do NOT call BringIntoView on the actual treeviewitem - this negates everything 
    //treeViewItem.BringIntoView(); 
} 
+0

¿Cuál es la parte de XAML para esto, por favor? Traté de adaptar algunos otros fragmentos XAML de esta página, pero no funcionaría para un error que no entiendo. – ygoe

+0

No importa, lo descubrí. Debe eliminar el "static" de la firma del método anterior, luego funciona el siguiente XAML: ygoe

12

utilizar una propiedad de dependencia en un disparador IsSelected:

<Style TargetType="{x:Type TreeViewItem}"> 
<Style.Triggers> 
    <Trigger Property="IsSelected" Value="True"> 
    <Setter Property="commands:TreeViewItemBehavior.BringIntoViewWhenSelected" Value="True" /> 
    </Trigger> 
</Style.Triggers> 

Aquí está el código de la propiedad de dependencia:

public static bool GetBringIntoViewWhenSelected(TreeViewItem treeViewItem) 
{ 
    return (bool)treeViewItem.GetValue(BringIntoViewWhenSelectedProperty); 
} 

public static void SetBringIntoViewWhenSelected(TreeViewItem treeViewItem, bool value) 
{ 
    treeViewItem.SetValue(BringIntoViewWhenSelectedProperty, value); 
} 

public static readonly DependencyProperty BringIntoViewWhenSelectedProperty = 
    DependencyProperty.RegisterAttached("BringIntoViewWhenSelected", typeof(bool), 
    typeof(TreeViewItemBehavior), new UIPropertyMetadata(false, OnBringIntoViewWhenSelectedChanged)); 

static void OnBringIntoViewWhenSelectedChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e) 
{ 
    TreeViewItem item = depObj as TreeViewItem; 
    if (item == null) 
    return; 

    if (e.NewValue is bool == false) 
    return; 

    if ((bool)e.NewValue) 
    item.BringIntoView(); 
} 
+1

Esta solución funciona incluso cuando establece la selección desde el código. Las otras variantes solo funcionan si presionas manualmente en un nodo del árbol. – alexandrudicu

+0

Esto es genial, funcionó como un encanto! –

+1

Al menos debe haber una referencia a la fuente original: [Introducción a los comportamientos vinculados en WPF] (https://www.codeproject.com/Articles/28959/Introduction-to-Attached-Behaviors-in-WPF) – bokibeg

13

Puede utilizar un EventSetter de estilo sencillo TreeViewItem para invocar un controlador de eventos cuando se selecciona el elemento. Luego llame a BringIntoView para el artículo.

+0

Downvoted esto por accidente; lo siento.Eso es lo que sucede cuando un gato camina sobre tu teclado. Necesitan un filtro de gato en SO. :-) –