2010-02-25 28 views
24

En mi aplicación, tengo un ListBox con elementos. La aplicación está escrita en WPF.WPF ListBox Desplácese hasta el final automáticamente

¿Cómo puedo desplazarme automáticamente al último elemento añadido? Quiero que el ScrollViewer se mueva al final de la lista cuando se haya agregado un nuevo elemento.

¿Hay algún evento como ItemsChanged? (no quiero utilizar el evento SelectionChanged)

Respuesta

0

usted podría intentar ListBox.ScrollIntoView() método, aunque hay algunos problems en algunos casos ...

Aquí se muestra un ejemplo de Tamir Khason: Auto scroll ListBox in WPF

+0

dos de los tres enlaces aquí están desaparecidos (y son los únicos dos con algún potencial para agregar algo útil a la pregunta) –

29

Prueba esto:

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

Esta es solo una opción válida, si el último elemento agregado es el último en la lista. Pero el último elemento agregado podría agregarse en la posición 0. – 0xBADF00D

+4

¡Esta respuesta debe aceptarse! @ 0xBADF00D Si ese es el caso, simplemente debe hacer 'lstBox.SelectedIndex = 0';) – DerpyNerd

+0

Funciona bien incluso con elementos duplicados, gracias. –

4

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

25

Tenga en cuenta que listBox.ScrollIntoView(listBox.Items[listBox.Items.Count - 1]); funciona solo si no tiene elementos duplicados. Si tiene elementos con los mismos contenidos, se desplazará al primer hallazgo.

Aquí está la solución que encontré:

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

Gracias. Funciona sin problemas para mí. Creo que deberías eliminar chatMessages a algo como myListBox. –

+2

Maravilloso, gracias. Para su información: debe agregar estas referencias a su proyecto: UIAutomationProvider y UIAutomationTypes – BCA

+0

Finalmente, después de horas de intentarlo y buscarlo, esta es la mejor solución para mí. – ck84vi

22

La forma más sencilla de hacerlo:

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

Siempre está trabajando para controles ListView y ListBox. Adjunte este código al evento listView.Items.SourceCollection.CollectionChanged y tendrá un comportamiento de desplazamiento automático completamente automático.

+1

Las otras soluciones simplemente no me funcionaron en absoluto. El código se ejecutó (se demostró en la depuración), pero no tuvo ningún efecto sobre el estado del control. Esto funcionó perfectamente la primera vez. –

+1

Esto podría no funcionar si usa una plantilla personalizada para 'ListBox' así que tenga cuidado. –

+0

Para cualquiera que quiera saber cómo adjuntar a CollectionChanged a su listbox: Después de 'InitializeComponent();' debe agregar '((INotifyCollectionChanged) .Items) .CollectionChanged + = YourListboxCollectionChanged;' – MarkusEgle

14

La mejor solución es usar el objeto ItemCollection dentro del control ListBox esta colección fue diseñada especialmente para los espectadores de contenido. Tiene un método predefinido para seleccionar el último artículo y guardar una referencia de posición del cursor ....

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

Un enfoque ligeramente diferente a las presentadas hasta ahora.

Puede utilizar el evento ScrollViewerScrollChanged y ver si aumenta el contenido del ScrollViewer.

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(); 
     }; 
    } 
} 

Esto evita algunos problemas con la unión al ListBoxItemsSource cambiante.

También se puede encontrar el ScrollViewer sin suponer que el ListBox está utilizando la plantilla de control predeterminada.

// 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; 
} 

A continuación, conecte este al evento ListBoxLoaded:

<ListBox Loaded="ListBox_OnLoaded" /> 

Esto podría ser fácilmente modificado para ser una propiedad adjunta, para que sea el propósito más general.

Cuestiones relacionadas