KonKarapas
KonKarapas

Reputation: 366

UWP Custom ListView to scroll down

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

Upvotes: 6

Views: 1799

Answers (2)

BCA
BCA

Reputation: 8506

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

Upvotes: 2

T&#243;th Tibor
T&#243;th Tibor

Reputation: 1565

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_

Upvotes: 16

Related Questions