2010-02-11 12 views
20

Quando si espande gli elementi nella vista albero in modo che lo scorrimento sia necessario, viene visualizzata una barra di scorrimento. Tuttavia, non scorre verso il basso per il ramo appena espanso di elementi: vengono ritagliati nella parte inferiore del controllo. Quindi, mentre continuo ad espandere gli oggetti nella parte inferiore dell'albero, devo continuare a scorrere manualmente verso il basso per vedere i nuovi bambini. Qualcuno ha un suggerimento su come farlo scorrere automaticamente per mostrare gli elementi appena espansi?WPF TreeView - Come scorrere in modo che il ramo espanso sia visibile

risposta

16

In TreeView, gestire l'evento TreeViewItem.Expanded (è possibile farlo a livello di TreeView a causa del bubbling degli eventi). Nel gestore espanso, chiama BringIntoView sull'oggetto TreeViewItem che ha generato l'evento.

Potrebbe essere necessario un po 'di tentativi ed errori per ottenere TreeViewItem nel codice del gestore di eventi. Penso (non ho controllato) che l'argomento del mittente per il gestore di eventi espanso sarà TreeView (poiché è lì che è collegato il gestore di eventi) piuttosto che TreeViewItem. E e.Source o e.OriginalSource può essere un elemento nel modello di dati di TreeViewItem. Quindi potresti aver bisogno di usare VisualTreeHelper per salire la struttura visuale per trovare TreeViewItem. Ma se si usa il debugger per ispezionare il mittente e RoutedEventArgs, questo dovrebbe essere banale da capire.

(Se riesci a farlo funzionare e vuoi raggrupparlo in modo da non dover collegare lo stesso gestore di eventi a ogni TreeView, dovrebbe essere facile incapsularlo come un attached behaviour che ti permetterà . per applicarlo in modo dichiarativo, anche attraverso uno stile)

+0

Che funziona perfettamente, ho pensato che ci sarebbe stato un problema perché voglio concentrarmi sugli elementi figlio espansi, non sull'elemento espanso, ma funziona esattamente come volevo. Grazie mille anche per il suggerimento comportamentale allegato, ancora meglio. – Jared

+0

In realtà questo funziona per il mio albero in cui completamente sovrascrivo il modello treeviewitem, ma non funziona per la mia vista ad albero più semplice in cui utilizzo il modello treeviewitem predefinito ... non so perché – Jared

2

Grazie alla risposta di itowlson, ecco il codice del gestore eventi esteso che funziona per entrambi i miei alberi

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

Qual è la parte XAML per questo per favore? Ho provato ad adattare alcuni altri frammenti XAML da questa pagina ma non funzionerebbe per un errore che non capisco. – ygoe

+0

Non importa, l'ho capito. È necessario rimuovere "statico" dalla firma del metodo sopra, quindi il seguente XAML funziona: ygoe

12

Utilizzare una proprietà di dipendenza su un grilletto IsSelected:

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

Ecco il codice della proprietà di dipendenza:

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

Questa soluzione funziona anche quando si imposta la selezione dal codice. Le altre varianti funzionano solo se si preme manualmente su un nodo dall'albero. – alexandrudicu

+0

Questo è fantastico, ha funzionato come un fascino! –

+1

Ci dovrebbe essere almeno un riferimento alla fonte originale: [Introduzione ai comportamenti associati in WPF] (https://www.codeproject.com/Articles/28959/Introduzione-Attached-Behaviors-in-WPF) – bokibeg

13

È possibile utilizzare un semplice EventSetter in stile TreeViewItem per invocare un gestore di eventi quando si seleziona la voce. Quindi chiama BringIntoView per l'oggetto.

+0

Downvoted questo per errore; scusa.Questo è quello che succede quando un gatto cammina sulla tua tastiera. Hanno bisogno di un filtro per gatti su SO. :-) –

Problemi correlati