New to Telerik UI for WPF? Download free 30-day trial

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

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

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

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

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

Find a runnable project of the previous example in the WPF Samples GitHub repository.