In my application, I have a ListBox
with items. The application is written in WPF.
How can I scroll automatically to the last added item? I want the
The most easiest way to achieve autoscrolling is to hook on the CollectionChanged event. Just add that functionality to a custom class which derives from ListBox control:
using System.Collections.Specialized;
using System.Windows.Controls;
using System.Windows.Media;
namespace YourProgram.CustomControls
{
public class AutoScrollListBox : ListBox
{
public AutoScrollListBox()
{
if (Items != null)
{
// Hook to the CollectionChanged event of your ObservableCollection
((INotifyCollectionChanged)Items).CollectionChanged += CollectionChange;
}
}
// Is called whenever the item collection changes
private void CollectionChange(object sender, NotifyCollectionChangedEventArgs e)
{
if (Items.Count > 0)
{
// Get the ScrollViewer object from the ListBox control
Border border = (Border)VisualTreeHelper.GetChild(this, 0);
ScrollViewer SV = (ScrollViewer)VisualTreeHelper.GetChild(border, 0);
// Scroll to bottom
SV.ScrollToBottom();
}
}
}
}
Add the namespace of the custom control to your WPF window and use the custom ListBox control:
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:YourProgram"
xmlns:cc="clr-namespace:YourProgram.CustomControls"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<cc:AutoScrollListBox ItemsSource="{Binding YourObservableCollection}"/>
</Window>
The best solution is to use the ItemCollection object inside the ListBox control this collection was specially designed to content viewers. It has a predefined method to select the last item and keep a cursor position reference....
myListBox.Items.MoveCurrentToLast();
myListBox.ScrollIntoView(myListBox.Items.CurrentItem);
Keep in mind that listBox.ScrollIntoView(listBox.Items[listBox.Items.Count - 1]);
works only if you have no duplicate items. If you have items with the same contents it scrolls down to the first find.
Here is the solution I found:
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);