かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

Universal Windows Platform appのListViewで追加されたアイテムに自動でスクロールさせたい

ということをしたいというケースがありました。

やり方としては、ItemsSourceがINotifyCollectionChangedだったら追加されたCollectionChangedを購読して追加された要素に対してScrollIntoViewしてやるだけです。 とりあえず、こういうBehaviorを作ってListViewにぽとっと落として実現しました。

public class ScrollBottomBehavior : DependencyObject, IBehavior
{
    public DependencyObject AssociatedObject
    {
        get;
        set;
    }

    private INotifyCollectionChanged currentItemsSource;

    public void Attach(DependencyObject associatedObject)
    {
        this.AssociatedObject = associatedObject;
        var lv = this.AssociatedObject as ListView;
        lv.DataContextChanged += (_, __) =>
        {
            if (this.currentItemsSource != null)
            {
                this.currentItemsSource.CollectionChanged -= this.CurrentItemsSource_CollectionChanged;
            }
            this.currentItemsSource = lv.ItemsSource as INotifyCollectionChanged;
            if (this.currentItemsSource != null)
            {
                this.currentItemsSource.CollectionChanged += this.CurrentItemsSource_CollectionChanged;
            }
        };
    }

    private void CurrentItemsSource_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.Action != NotifyCollectionChangedAction.Add)
        {
            return;
        }

        var item = e.NewItems.Cast<ChatMessageViewModel>().First();
        ((ListView)this.AssociatedObject).ScrollIntoView(item);
    }

    public void Detach()
    {
        if (this.currentItemsSource != null)
        {
            this.currentItemsSource.CollectionChanged -= this.CurrentItemsSource_CollectionChanged;
            this.currentItemsSource = null;
        }
    }
}