5

So, I have a listview and I want it whenever an item is created to scroll to that item (bottom). Because I am using MVVM I found really nice explanation on how to make a new control that inherits from listview that scrolls down. The problem is that this answer (the third) is referring to WPF 6 years ago. I am making a UWP app, so I copied the code and tried to format it to my needs. The following code doesn't give any error or exception but instead it loads the "ChatListView" as I call it perfectly and then does nothing. The comments are only a bit edited compared to the original code.

What can I do ? Thank you in advance!

public class ChatListView : ListView
{
    //Define the AutoScroll property. If enabled, causes the ListBox to scroll to 
    //the last item whenever a new item is added.
    public static readonly DependencyProperty AutoScrollProperty =
        DependencyProperty.Register(
            "AutoScroll",
            typeof(Boolean),
            typeof(ChatListView),
            new PropertyMetadata(
                true, //Default value.
                new PropertyChangedCallback(AutoScroll_PropertyChanged)));

    //Gets or sets whether or not the list should scroll to the last item 
    //when a new item is added.
    public bool AutoScroll
    {
        get { return (bool)GetValue(AutoScrollProperty); }
        set { SetValue(AutoScrollProperty, value); }
    }

    //Event handler for when the AutoScroll property is changed.
    //This delegates the call to SubscribeToAutoScroll_ItemsCollectionChanged().
    //d = The DependencyObject whose property was changed.</param>
    //e = Change event args.</param>
    private static void AutoScroll_PropertyChanged(
        DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        SubscribeToAutoScroll_ItemsCollectionChanged(
            (ChatListView)d,
            (bool)e.NewValue);
    }

    //Subscribes to the list items' collection changed event if AutoScroll is enabled.
    //Otherwise, it unsubscribes from that event.
    //For this to work, the underlying list must implement INotifyCollectionChanged.
    //
    //(This function was only creative for brevity)

    //listBox = The list box containing the items collection.
    //subscribe = Subscribe to the collection changed event?
    private static void SubscribeToAutoScroll_ItemsCollectionChanged(
        ChatListView listView, bool subscribe)
    {
        INotifyCollectionChanged notifyCollection =
            listView as INotifyCollectionChanged;
        if (notifyCollection != null)
        {
            if (subscribe)
            {
                //AutoScroll is turned on, subscribe to collection changed events.
                notifyCollection.CollectionChanged +=
                    listView.AutoScroll_ItemsCollectionChanged;
            }
            else
            {
                //AutoScroll is turned off, unsubscribe from collection changed events.
                notifyCollection.CollectionChanged -=
                    listView.AutoScroll_ItemsCollectionChanged;
            }
        }
    }

    //Event handler called only when the ItemCollection changes
    //and if AutoScroll is enabled.

    //sender = The ItemCollection.
    //e = Change event args.
    private void AutoScroll_ItemsCollectionChanged(
        object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.Action == NotifyCollectionChangedAction.Add)
        {
            int count = Items.Count;
            ScrollIntoView(Items[count - 1]);
        }
    }

    //Constructor a new ChatListView.
    public ChatListView()
    {
        //Subscribe to the AutoScroll property's items collection 
        //changed handler by default if AutoScroll is enabled by default.
        SubscribeToAutoScroll_ItemsCollectionChanged(
            this, (bool)AutoScrollProperty.GetMetadata(typeof(ChatListView)).DefaultValue);
    }
}
Community
  • 1
  • 1
KonKarapas
  • 356
  • 3
  • 15

2 Answers2

14

If you want to create a chat application you can use the ItemsStackPanel's ItemsUpdatingScrollMode particular property to KeepLastItemInView value to scroll to the latest item.

Usage:

<ListView>
    <ListView.ItemsPanel>
        <ItemsPanelTemplate>
            <ItemsStackPanel ItemsUpdatingScrollMode="KeepLastItemInView" />
        </ItemsPanelTemplate>
    </ListView.ItemsPanel>
</ListView>

Note: KeepLastItemInView enum member was introduced in the 14393 SDK.

Related link: https://learn.microsoft.com/en-us/uwp/api/Windows.UI.Xaml.Controls.ItemsStackPanel#properties_

Tóth Tibor
  • 1,526
  • 12
  • 21
  • 2
    That's even more than I was asking... It doesn't only scroll down when you add something on the list, but also if you are not at viewing the last item (for example if you want to look at previous messages), it doesn't scroll down. Perfect!!! – KonKarapas Mar 18 '17 at 20:19
  • Exactly what I need! Thank you! – Steve Jun 02 '21 at 15:53
2

The accepted answer is pretty nice. However I there is one thing it won't do (at least if I simply copy and paste the above XAML): it won't do its intended scrolling if, say, the user was away from that page while new items were added, and then they navigated to the page.

For that I had to hook into

protected override void OnNavigatedTo(NavigationEventArgs e)
{
   base.OnNavigatedTo(e);

   if (MyListView.Items.Count == 0)
      return;

   object lastItem = MyListView.Items[MyListView.Items.Count - 1];
   MyListView.ScrollIntoView(lastItem);
}
BCA
  • 7,776
  • 3
  • 38
  • 53