Edit this page

Scroll Item into View

The RadTreeListView API offers ScrollIntoView support through the following methods:

The goal of this tutorial is to demonstrate how you can bring a particular, deeply nested TreeListViewRow into view. This might be helpful if you need a fast hierarchy control with many nested levels and RadTreeView is slow in your particular scenario with bring into view. This example is configured in such way that RadTreeListView behaves and feels much like RadTreeView.

Initial setting up of the project

For the purpose of this example, you will need to create an empty application project and open it in Visual Studio. The first step is to add references to the following assemblies:

  • Telerik.Windows.Controls

  • Telerik.Windows.Controls.GridView

  • Telerik.Windows.Controls.Input

  • Telerik.Windows.Data

Then you can define the controls in your view. As the purpose of this tutorial is to demonstrate how to implement the ScrollIntoView methods, we won't focus on the definitions of the controls in xaml.

<Grid x:Name="LayoutRoot" Background="White">
    <Grid.RowDefinitions>
        <RowDefinition Height="40" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>

    <Grid.Resources>
        <Style TargetType="telerik:RadTreeListView">
            <Setter Property="VerticalGridLinesBrush" Value="{x:Null}" />
            <Setter Property="RowIndicatorVisibility" Value="Collapsed" />
            <Setter Property="IsFilteringAllowed" Value="False" />
            <Setter Property="CanUserFreezeColumns" Value="False" />
            <Setter Property="CanUserDeleteRows" Value="False" />
            <Setter Property="AutoGenerateColumns" Value="False" />
            <Setter Property="ShowGroupPanel" Value="False" />
            <Setter Property="ShowColumnHeaders" Value="False" />
            <Setter Property="AutoExpandGroups" Value="True" />
            <Setter Property="GridLinesVisibility" Value="None" />
            <Setter Property="RowHeight" Value="24" />
            <Setter Property="BorderThickness" Value="0" />
            <Setter Property="BorderBrush" Value="{x:Null}" />
        </Style>
    </Grid.Resources>

    <telerik:RadTreeListView x:Name="treeList"
                             Grid.Row="1"
                             Width="500"                                 
                             IsExpandableBinding="{Binding IsExpandable}"
                             TreeLinesVisibility="Visible">
        <telerik:RadTreeListView.ChildTableDefinitions>
            <telerik:TreeListViewTableDefinition ItemsSource="{Binding Children}" />
        </telerik:RadTreeListView.ChildTableDefinitions>

        <telerik:RadTreeListView.Columns>
            <telerik:GridViewDataColumn DataMemberBinding="{Binding Name}" Header="Name" />
        </telerik:RadTreeListView.Columns>
    </telerik:RadTreeListView>

    <StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
        <telerik:RadButton Width="350"
                           Click="RadButton_Click_1"
                           Content="ScrollIntoViewAsync Recursively" />
        <telerik:RadButton Width="350"
                           Click="RadButton_Click_2"
                           Content="Expand in a Loop and Then Scroll" />
    </StackPanel>
</Grid>

The next step is to define the business object.

public class DataItem : ViewModelBase
    {
        private string name;
        public string Name
        {
            get { return this.name; }
            set
            {
                if (this.name != value)
                {
                    this.name = value;
                    this.OnPropertyChanged("Name");
                }
            }
        }

        private ObservableCollection<DataItem> children;
        public ObservableCollection<DataItem> Children
        {
            get
            {
                if (children == null)
                {
                    children = new ObservableCollection<DataItem>();
                    for (int i = 0; i < 100; i++)
                    {
                        DataItem item = new DataItem() { Name = this.Name + "." + i};
                        children.Add(item);
                    }
                }
                return children;
            }
        }

        public bool IsExpandable
        {
            get
            {
                return true;
            }
        }
    }
Public Class DataItem
    Inherits ViewModelBase

        Private name_Renamed As String
        Public Property Name() As String
            Get
                Return Me.name_Renamed
            End Get
            Set(ByVal value As String)
                If Me.name_Renamed <> value Then
                    Me.name_Renamed = value
                    Me.OnPropertyChanged("Name")
                End If
            End Set
        End Property

        Private children_Renamed As ObservableCollection(Of DataItem)
        Public ReadOnly Property Children() As ObservableCollection(Of DataItem)
            Get
                If children_Renamed Is Nothing Then
                    children_Renamed = New ObservableCollection(Of DataItem)()
                    For i As Integer = 0 To 99
                        Dim item As New DataItem() With {.Name = Me.Name & "." & i}
                        children_Renamed.Add(item)
                    Next i
                End If
                Return children_Renamed
            End Get
        End Property

        Public ReadOnly Property IsExpandable() As Boolean
            Get
                Return True
            End Get
        End Property
End Class

What comes next, is to populate with data.

public partial class Example : UserControl
{
    DateTime listBringStart;
    private ObservableCollection<DataItem> list;

    public Example()
    {
        InitializeComponent();
        this.LoadData();
    }

    private void LoadData()
    {
        list = new ObservableCollection<DataItem>();
        for (int i = 0; i < 100; i++)
        {
            DataItem root = new DataItem() { Name = "Item " + i };
            list.Add(root);
        }
        this.treeList.ItemsSource = list;
    }
}
Partial Public Class Example
    Inherits UserControl

    Private listBringStart As Date
    Private list As ObservableCollection(Of DataItem)

    Public Sub New()
        InitializeComponent()
        Me.LoadData()
    End Sub

    Private Sub LoadData()
        list = New ObservableCollection(Of DataItem)()
        For i As Integer = 0 To 99
            Dim root As New DataItem() With {.Name = "Item " & i}
            list.Add(root)
        Next i
        Me.treeList.ItemsSource = list
    End Sub
End Class

ScrollIntoViewAsync()

Clicking the first button will bring an item which is 20 levels deep with updating the UI on every level expansion. For this purpose we will use the ScrollIntoViewAsync (Object dataItem, Action(FrameworkElement) scrollFinishedCallback, bool expandItem) method, which scrolls the row containing the data item into view in an asynchronous manner.

private void RadButton_Click_1(object sender, RoutedEventArgs e)
{
    this.listBringStart = DateTime.Now;
    this.ScrollIntoViewRecursive(0, list[85]);
}

private void ScrollIntoViewRecursive(int level, DataItem item)
{
    if (level >= 20)
    {
        MessageBox.Show(DateTime.Now.Subtract(this.listBringStart).TotalSeconds.ToString() + " sec.");
        return;
    }
    var newItem = item.Children[85];
    this.treeList.ScrollIntoViewAsync(item, (f) => { ScrollIntoViewRecursive(++level, newItem); }, true);
}
Private Sub RadButton_Click_1(ByVal sender As Object, ByVal e As RoutedEventArgs)
    Me.listBringStart = Date.Now
    Me.ScrollIntoViewRecursive(0, list(85))
End Sub

Private Sub ScrollIntoViewRecursive(ByVal level As Integer, ByVal item As DataItem)
    If level >= 20 Then
        MessageBox.Show(Date.Now.Subtract(Me.listBringStart).TotalSeconds.ToString() & " sec.")
        Return
    End If
    Dim newItem = item.Children(85)
    Me.treeList.ScrollIntoViewAsync(item, Sub(f)
        level += 1
        ScrollIntoViewRecursive(level, newItem)
    End Sub, True)
End Sub

ScrollIntoView()

Clicking the second button will update the UI only when the bring operation is finished. Here we are using the ScrollIntoView(Object dataItem, bool expandItem) method, which scrolls the row containing the data item into view.

private void RadButton_Click_2(object sender, RoutedEventArgs e)
{
    DateTime startTime = DateTime.Now;

    DataItem start = this.list[85];
    for (int i = 0; i < 20; i++)
    {
        this.treeList.ExpandHierarchyItem(start);
        start = start.Children[85];
    }
    this.treeList.ScrollIntoView(start, false);
    this.treeList.SelectedItems.Add(start);
    DateTime end = DateTime.Now;
    MessageBox.Show(end.Subtract(startTime).TotalSeconds.ToString() + " sec.");
}
Private Sub RadButton_Click_2(ByVal sender As Object, ByVal e As RoutedEventArgs)
    Dim startTime As Date = Date.Now

    Dim start As DataItem = Me.list(85)
    For i As Integer = 0 To 19
        Me.treeList.ExpandHierarchyItem(start)
        start = start.Children(85)
    Next i
    Me.treeList.ScrollIntoView(start, False)
    Me.treeList.SelectedItems.Add(start)
    Dim [end] As Date = Date.Now
    MessageBox.Show([end].Subtract(startTime).TotalSeconds.ToString() & " sec.")
End Sub

Please have in mind that running the application without debugger (Ctrl + F5 when in VS) will result in faster user experience.

You can download a runnable project of the demonstrated example from our online SDK repository here, after navigating to TreeView/TreeListViewBringItemIntoView.

See Also

Was this article helpful? Yes No

Give article feedback

Tell us how we can improve this article

Dummy