2010-02-25 12 views
24

In meiner Anwendung habe ich eine ListBox mit Elementen. Die Anwendung ist in WPF geschrieben.WPF ListBox Scrollen, um automatisch zu beenden

Wie scrolle ich automatisch zum letzten hinzugefügten Element? Ich möchte, dass die ScrollViewer an das Ende der Liste verschoben wird, wenn ein neues Element hinzugefügt wurde.

Gibt es ein Ereignis wie ItemsChanged? (Ich will nicht das SelectionChanged Ereignis verwenden)

Antwort

0

Sie könnten ListBox.ScrollIntoView() Methode versuchen, obwohl es einige problems in einigen Fällen sind ...

Hier ist ein Beispiel von Tamir Khason: Auto scroll ListBox in WPF

+0

zwei der drei Links hier sind verstorben (und sie sind die einzigen beiden mit einem Potenzial, etwas Nützliches zu der Frage hinzuzufügen) –

29

Versuchen Sie folgendes:

lstBox.SelectedIndex = lstBox.Items.Count -1 
lstBox.ScrollIntoView(lstBox.SelectedItem) 
+0

Dies ist nur eine gültige Option, wenn das letzte hinzugefügte Element das letzte in der Liste ist. Aber der letzte hinzugefügte Eintrag könnte an Position 0 hinzugefügt werden. – 0xBADF00D

+4

Diese Antwort sollte akzeptiert werden! @ 0xBADF00D Wenn das der Fall ist, sollten Sie nur 'lstBox.SelectedIndex = 0';) – DerpyNerd

+0

Funktioniert auch mit doppelten Elementen, danke. –

4

listBox.ScrollIntoView (listBox.Items [listBox.Items.Count - 1]);

25

Beachten Sie, dass listBox.ScrollIntoView(listBox.Items[listBox.Items.Count - 1]); nur funktioniert, wenn Sie keine doppelten Elemente haben. Wenn Sie Objekte mit demselben Inhalt haben, scrollt es zum ersten gefundenen Objekt. Hier

ist die Lösung, die ich gefunden:

ListBoxAutomationPeer svAutomation = (ListBoxAutomationPeer)ScrollViewerAutomationPeer.CreatePeerForElement(myListBox); 

IScrollProvider scrollInterface = (IScrollProvider)svAutomation.GetPattern(PatternInterface.Scroll); 
System.Windows.Automation.ScrollAmount scrollVertical = System.Windows.Automation.ScrollAmount.LargeIncrement; 
System.Windows.Automation.ScrollAmount scrollHorizontal = System.Windows.Automation.ScrollAmount.NoAmount; 
//If the vertical scroller is not available, the operation cannot be performed, which will raise an exception. 
if (scrollInterface.VerticallyScrollable) 
    scrollInterface.Scroll(scrollHorizontal, scrollVertical); 
+0

Danke. Funktioniert einwandfrei für mich. Ich denke, du solltest chatMessages auf etwas wie myListBox entfernen. –

+2

Wunderbar, danke. FYI für andere: müssen diese Referenzen zu Ihrem Projekt hinzufügen: UIAutomationProvider und UIAutomationTypes – BCA

+0

Endlich nach stundenlangem Ausprobieren und Suchen ist das die beste Lösung für mich. – ck84vi

22

Der einfachste Weg, dies zu tun:

if (VisualTreeHelper.GetChildrenCount(listView) > 0) 
{ 
    Border border = (Border)VisualTreeHelper.GetChild(listView, 0); 
    ScrollViewer scrollViewer = (ScrollViewer)VisualTreeHelper.GetChild(border, 0); 
    scrollViewer.ScrollToBottom(); 
} 

Es ist immer funktioniert für Listview und ListBox Kontrollen. Fügen Sie diesen Code an das Ereignis listView.Items.SourceCollection.CollectionChanged an, und Sie haben ein vollautomatisches automatisches Scrollverhalten.

+1

Die anderen Lösungen funktionierten einfach nicht für mich. Der Code wurde ausgeführt (im Debugging getestet), hatte jedoch keine Auswirkung auf den Status des Steuerelements. Das hat beim ersten Mal perfekt funktioniert. –

+1

Dies funktioniert möglicherweise nicht, wenn Sie eine benutzerdefinierte Vorlage für die 'ListBox' verwenden, seien Sie also vorsichtig. –

+0

Für jeden, der wissen möchte, wie man an CollectionChanged an Ihre Listbox anfügt: Nach 'InitializeComponent();' müssen Sie hinzufügen '((INotifyCollectionChanged) .Items) .CollectionChanged + = YourListboxCollectionChanged;' – MarkusEgle

14

Die beste Lösung ist die Verwendung des ItemCollection-Objekts innerhalb des ListBox-Steuerelements Diese Sammlung wurde speziell für Inhaltsbetrachter entwickelt. Es hat eine vordefinierte Methode das letzte Element und halten eine Cursorposition Bezug zu wählen ....

myListBox.Items.MoveCurrentToLast(); 
myListBox.ScrollIntoView(myListBox.Items.CurrentItem); 
0

Eine etwas andere Herangehensweise an die bisher vorgestellt.

Sie könnten das Ereignis ScrollViewerScrollChanged verwenden und achten Sie darauf, dass der Inhalt der ScrollViewer größer wird.

private void ListBox_OnLoaded(object sender, RoutedEventArgs e) 
{ 
    var listBox = (ListBox) sender; 

    var scrollViewer = FindScrollViewer(listBox); 

    if (scrollViewer != null) 
    { 
     scrollViewer.ScrollChanged += (o, args) => 
     { 
      if (args.ExtentHeightChange > 0) 
       scrollViewer.ScrollToBottom(); 
     }; 
    } 
} 

Dies vermeidet einige Probleme mit der Bindung an den ListBoxItemsSource Wechsel. Die ScrollViewer kann auch ohne die Annahme gefunden werden, dass ListBox die Standardsteuervorlage verwendet.

// Search for ScrollViewer, breadth-first 
private static ScrollViewer FindScrollViewer(DependencyObject root) 
{ 
    var queue = new Queue<DependencyObject>(new[] {root}); 

    do 
    { 
     var item = queue.Dequeue(); 

     if (item is ScrollViewer) 
      return (ScrollViewer) item; 

     for (var i = 0; i < VisualTreeHelper.GetChildrenCount(item); i++) 
      queue.Enqueue(VisualTreeHelper.GetChild(item, i)); 
    } while (queue.Count > 0); 

    return null; 
} 

Dann befestigen diese an die ListBoxLoaded Veranstaltung:

<ListBox Loaded="ListBox_OnLoaded" /> 

Dies könnte leicht zu sein, eine angefügte Eigenschaft modifiziert werden, so dass es für allgemeine Zwecke zu machen.