Tuesday, December 7, 2010

How to add “ScrollIntoView” to an ItemsControl

The ListBox control (in Silverlight or WPF) has a handy method called ScrollIntoView that forces a listbox scroll so that the parsed item is in view.  This post will describe how to add this capability to an ItemsControl.

Firstly, to enable vertical scrolling in an ItemsControl apply the following template.

<ItemsControl x:Name="myItemsControl">

    <ItemsControl.Template>
        <ControlTemplate>
            <ScrollViewer Padding="{TemplateBinding Padding}">
                <ItemsPresenter />
            </ScrollViewer>
        </ControlTemplate>
    </ItemsControl.Template>
</ItemsControl>

Next, add the following class that extends the ItemsControl class with an overloaded “Scroll Into View” method.

using System.Windows;
using System.Windows.Controls;

namespace myNamespace {
    public static class Extensions {
        public static void ScrollIntoView(
this ItemsControl control,
object item) {
            FrameworkElement framework =
control.ItemContainerGenerator.ContainerFromItem(item)
as FrameworkElement;
            if (framework == null) { return; }
            framework.BringIntoView();
        }
        public static void ScrollIntoView(this ItemsControl control) {
            int count = control.Items.Count;
            if (count == 0) { return; }
            object item = control.Items[count - 1];
            control.ScrollIntoView(item);
        }
    }
}

With this extension you can force the ItemsControl to scroll to a specific item, or alternatively, using the overloaded method, simply scroll to the last item in the collection.  For example.

this.myItemsControl.ScrollIntoView();

6 comments:

  1. hi Richie,thanks for your experience sharing! your 3D terrain map demo is excellent,but when i try transform it work with balder 0.8.8.9, the UpdateElevation method looks not work well.is the problem of heightmap's member SetHeightForGridPoint?
    thank you in advance!
    best wishes,one of your fans ;-)

    ReplyDelete
  2. Unfortuantely, this does not work if using a virtualized panel inside the ItemsControl. It was what we had prior to implementing virtualization. In this case, it will only work for things that are visibly shown since non-displayed item FrameworkElements do not exist (are not created) until scrolled into view. Those that are scrolled off are then destroyed or reused. This makes BringIntoView useless since you need a FrameworkElement and you only null back when you ask for it. Unfortunate, since we have gone virtual for all our controls for load speed and lower memory usage and discovered the issue. On goes the search for a better answer.

    ReplyDelete
  3. Thanks! Exactly what I needed!

    ReplyDelete
  4. how can i add button in this scrollviewer ?

    ReplyDelete
  5. This doesn't work on win 8.1 metro app. There is no frameworkelement.bringintoview(). Also, control.scrollintovew() causes a stack overflow.

    ReplyDelete