Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ListView scroll to last item WPF C#

Tags:

c#

wpf

how to make scroll rule always at end of the ListView automatic without focus in WPF?

like image 384
kartal Avatar asked Sep 28 '10 13:09

kartal


1 Answers

The answers from @pduncan and @MattBurland both have some problems, primarily that they fail to unregister the behaviour properly.

This implementation stores the handler in another attached property so that you can toggle the behaviour on and off, perhaps through a binding.

Note that this applies to ListView. If you are using ListBox, change occurrences of ListView to ListBox.

public static class ListViewExtensions
{
    public static readonly DependencyProperty AutoScrollToEndProperty = DependencyProperty.RegisterAttached("AutoScrollToEnd", typeof(bool), typeof(ListViewExtensions), new UIPropertyMetadata(OnAutoScrollToEndChanged));
    private static readonly DependencyProperty AutoScrollToEndHandlerProperty = DependencyProperty.RegisterAttached("AutoScrollToEndHandler", typeof(NotifyCollectionChangedEventHandler), typeof(ListViewExtensions));

    public static bool GetAutoScrollToEnd(DependencyObject obj) => (bool)obj.GetValue(AutoScrollToEndProperty);
    public static void SetAutoScrollToEnd(DependencyObject obj, bool value) => obj.SetValue(AutoScrollToEndProperty, value);

    private static void OnAutoScrollToEndChanged(DependencyObject s, DependencyPropertyChangedEventArgs e)
    {
        var listView = s as ListView;

        if (listView == null)
            return;

        var source = (INotifyCollectionChanged)listView.Items.SourceCollection;

        if ((bool)e.NewValue)
        {
            NotifyCollectionChangedEventHandler scrollToEndHandler = delegate
            {
                if (listView.Items.Count <= 0)
                    return;
                listView.Items.MoveCurrentToLast();
                listView.ScrollIntoView(listView.Items.CurrentItem);
            };

            source.CollectionChanged += scrollToEndHandler;

            listView.SetValue(AutoScrollToEndHandlerProperty, scrollToEndHandler);
        }
        else
        {
            var handler = (NotifyCollectionChangedEventHandler)listView.GetValue(AutoScrollToEndHandlerProperty);

            source.CollectionChanged -= handler;
        }
    }
}

Use it like this:

<ListView local:ListViewExtensions.AutoScrollToEnd="{Binding Path=AutoScroll}">

I also made it a a static class, as you don't need to instantiate it (nor does it need to derive from DependencyObject). The cast to INotifyCollectionChanged was changed so that errors surface as cast exceptions, not NREs.

like image 158
Drew Noakes Avatar answered Sep 23 '22 13:09

Drew Noakes