Reputation: 13360
Is there a way to keep a ListView scrolling vertically as data is updated via a binding to the ListView's ItemsSource property? I can't seem to find a property in either the ListView or its underlying GridView control to achieve the desired result. I would like it to scroll so that the newest information is always visible to the user. A scroll bar already appears as the rows add to the control but the most current row is not presented.
Should I consider using a different type of control that has auto-scroll capability? I only have two columns: one contains DateTimes and the other contains a simple string. I'm starting to think that my control choice may be too limited.
My XAML looks roughly like this:
<ListView ItemsSource="{Binding Updates}">
<ListView.View>
<GridView>
<GridViewColumn Header="Timestamp" DisplayMemberBinding="{Binding TimeStamp}"/>
<GridViewColumn DisplayMemberBinding="{Binding UpdateString}" />
</GridView>
</ListView.View>
</ListView>
Upvotes: 1
Views: 2891
Reputation: 13360
I found away to expose the ListView
's ScrollViewer object to manipulate scrolling. My DataContext
contains a collection derived from ObservableCollection
and in the code behind I wired an eventhandler to the CollectionChanged
event. I used a Decorator
to expose the the first child of the ListView
(the border) and it's child is the ScrollViewer
. From there I call the ScrollToBottom()
method to attain the desired behavior.
In the code behind for my View which contains the ListView
, this is how it's coded
MyViewModel viewModel = DataContext as MyViewModel;
viewModel.MyCollection.CollectionChanged += (sender,e) =>
{
if(e.NewItems != null)
{
Decorator border = VisualTreeHelper.GetChild(SummaryListView, 0) as Decorator;
ScrollViewer scroll = border.Child as ScrollViewer;
scroll.ScrollToBottom();
}
};
I found how to expose the ScrollViewer
on Anshulee's WindowsClient blog post.
Edit
Previously, I was checking if the max number of items in the custom collection was met and then scrolled to bottom. That did not work so well with different screen resolutions because the app might display 15 lines in the ListView
on one machine and 25 lines on another. So now I always have it scroll to bottom to bring the newest item into view.
Upvotes: 2
Reputation: 2103
A Listview has a method called ScrollIntoView(object item)
.
This will scroll the Listview to the position where the specified item is.
When you have a collection that is binded to the Listview, you can call this method when your collection has changed, something like:
private void myCollectionChanged()
{
myListView.ScrollIntoView(myCollection.Last());
}
Upvotes: 0
Reputation: 24723
I'm pretty sure that a VirtualizingStackPanel
is being used under the covers...which means that the items do no exist until they are needed. Therefore if you have 15000 items, rendering those 15000 items before needed makes no sense.
An easier approach may be to force a sort so the newest data remains on the top. It will then give you the appearance of pushing items down but they will be the oldest items so scrolling to see them doesn't matter unless the user initiates it.
Upvotes: 0
Reputation: 4332
you should use a scrollviewer object, it will automatically scroll when needed its contents (you can also specify if you always want horizontal or vertical scroll regardless where it's needed or not, and some other things as well)
<ScrollViewer>
<GridView>
<!-- gridview definition -->
<GridView>
</ScrollViewer>
more info on MSDN
Upvotes: 1