TreeListView, Virtualization and ScrollIntoViewAsync

4 posts, 0 answers
  1. Sodi We
    Sodi We avatar
    160 posts
    Member since:
    Apr 2010

    Posted 27 Mar 2014 Link to this post

    Hello everyone,

    We were having issues with the 'ScrollItemIntoViewAsync' method.
    When virtualization is turned on, none of the proposed solutions found on the internet worked (or not atleast a 100%).

    E.g. when I'd randomly select an item from my entire collection (hierarchy depth could easily go down 30 levels or more) it wouldn't always correctly scroll to that row.

    However, we managed to come up with a pretty straight forward solution which could be implemented by pretty much anyone. (And hopefully, internally by Telerik inside the grid controls as well)

    The idea is that the root items in a hierarchical grid are always present, and we found that ScrollIntoViewAsync always worked when trying to scroll to root items.
    So we'd first scroll to the root item, then to the next item inside the root item's collection and so on and so on untill we reached the actual item we were supposed to scroll to.

    Prerequistes:

    1.) The row item's view model must implement a specific interface (we called it IScrollableGridItem) that contains a "GetScrollList()" function which returns a list of objects that contains all the parents of that item and itself, in reversed order (eg the root item will be the first in the list and the actual item is the last)
    2.) The row item's view model must have a reference to its parent item (to basically make the "GetScrollList()" work)
    3.) Row height should be set on the grid (it doesn't seem to always work with no specified row height)

    We made a custom behavior that allowed us to have a SelectedItem at any given time, regardless of the grid SelectionMode & SelectionUnit.


    Inside this behavior, when the SelectedItem was being set via the ViewModel we added the following code:

    001.private object actualScrollToItem = null;
    002.private object currentScrollToItem = null;
    003.private List<object> scrollItems = null;
    004.private int scrollToItemAttemptCount = 0;
    005. 
    006.private void SelectedItemTargetUpdated(object sender, DataTransferEventArgs e)
    007.{
    008.    var item = GetValue(e.Property);
    009. 
    010.    /* SNIP IRRELEVANT CODE TO SCROLLING */
    011.     
    012.    actualScrollToItem = item;
    013. 
    014.    if (actualScrollToItem is IScrollableGridItem)
    015.    {
    016.        Console.WriteLine("-- BEGIN SCROLLING TO {0} --", actualScrollToItem.GetHashCode());
    017. 
    018.        var tmp = item as IScrollableGridItem;
    019. 
    020.        // Get a list of items to scroll to
    021.        scrollItems = tmp.GetScrollList();
    022. 
    023.        // Start scrolling to the first item
    024.        currentScrollToItem = scrollItems.First();
    025. 
    026.        GridControl.ScrollIntoViewAsync(currentScrollToItem, Scroll, ScrollFailed);
    027. 
    028.    }
    029.    else
    030.    {
    031.        // Attempt is not IScrollable, attempt to scroll anyway
    032.        currentScrollToItem = actualScrollToItem;
    033.        Console.WriteLine("Item is not IScrollable");
    034.        GridControl.ScrollIntoViewAsync(actualScrollToItem, Scroll, ScrollFailed);
    035.    }
    036.}
    037. 
    038.private void Scroll(FrameworkElement arg)
    039.{
    040.    Console.WriteLine("Succesfully scrolled to {0}", currentScrollToItem.GetHashCode());
    041. 
    042.    scrollToItemAttemptCount = 0;
    043. 
    044.    var row = arg as GridViewRow;
    045. 
    046.    if (actualScrollToItem == currentScrollToItem)
    047.    {
    048.        Console.WriteLine("Reached actual scroll item");
    049.        Console.WriteLine("-- END SCROLLING TO {0} --", actualScrollToItem.GetHashCode());
    050.        GridControl.ClearSelection();
    051.        GridControl.SelectedItems.Add(currentScrollToItem);
    052. 
    053.        actualScrollToItem = null;
    054.        currentScrollToItem = null;
    055.        scrollItems = null;
    056. 
    057.        if (row != null)
    058.        {
    059.            row.IsCurrent = true;
    060.            row.Focus();
    061.            row.BringIntoView();
    062.        }
    063.    }
    064.    else
    065.    {
    066.        if (row != null && row.IsExpandable)
    067.        {
    068.            row.IsExpanded = true;
    069.        }
    070. 
    071.        var idx = scrollItems.IndexOf(currentScrollToItem);
    072.        currentScrollToItem = scrollItems[idx + 1];
    073. 
    074.        GridControl.ScrollIntoViewAsync(currentScrollToItem, Scroll, ScrollFailed);
    075.    }
    076.     
    077.}
    078. 
    079.private void ScrollFailed()
    080.{
    081.    scrollToItemAttemptCount++;
    082. 
    083.    Console.WriteLine("Failed to scroll to {0}. Already tried {1} times", currentScrollToItem.GetHashCode(), scrollToItemAttemptCount);
    084. 
    085.    if (currentScrollToItem == null)
    086.    {
    087.        Console.WriteLine("Stopped attempting to scroll because currentScrollToItem is NULL");
    088.        scrollToItemAttemptCount = 0;
    089.        return;
    090.    }
    091. 
    092.    if (scrollToItemAttemptCount < 5)
    093.    {
    094.        GridControl.ScrollIntoViewAsync(currentScrollToItem, Scroll, ScrollFailed);
    095.    }
    096.    else
    097.    {
    098.        currentScrollToItem = null;
    099.        actualScrollToItem = null;
    100.        scrollToItemAttemptCount = 0;
    101.    }
    102.     
    103.}

    And for the sake of completeness, here's the code for the "GetParents()" implementation:

    01.public List<object> GetParents()
    02.{
    03.    List<object> result = new List<object>();
    04. 
    05.    var tmp = Parent;
    06. 
    07.    // Get all my parents
    08.    while (tmp != null)
    09.    {
    10.        result.Add(tmp);
    11. 
    12.        tmp = tmp.Parent;
    13.    }
    14. 
    15.    // Add myself to the list
    16.    result.Add(this);
    17. 
    18.    // We want the root item to be first in the list and myself last
    19.    result.Reverse();
    20. 
    21.    return result;
    22.}

  2. Sodi We
    Sodi We avatar
    160 posts
    Member since:
    Apr 2010

    Posted 27 Mar 2014 Link to this post

    Sodi We said:
    And for the sake of completeness, here's the code for the "GetParents()" implementation:

    01.public List<object> GetParents()
    02.{
    03.    List<object> result = new List<object>();
    04. 
    05.    var tmp = Parent;
    06. 
    07.    // Get all my parents
    08.    while (tmp != null)
    09.    {
    10.        result.Add(tmp);
    11. 
    12.        tmp = tmp.Parent;
    13.    }
    14. 
    15.    // Add myself to the list
    16.    result.Add(this);
    17. 
    18.    // We want the root item to be first in the list and myself last
    19.    result.Reverse();
    20. 
    21.    return result;
    22.}


    That should be "GetScrollList" instead of "GetParents" :-)

  3. UI for WPF is Visual Studio 2017 Ready
  4. Sodi We
    Sodi We avatar
    160 posts
    Member since:
    Apr 2010

    Posted 27 Mar 2014 Link to this post

    Since i'm not able to modify my initial post, could a moderator be so kind as to fix the typo in the topic title?

    ScrollItemIntoViewAsync should be ScrollIntoViewAsync
  5. Dimitrina
    Admin
    Dimitrina avatar
    3769 posts

    Posted 01 Apr 2014 Link to this post

    Hi,

    You can check our Scroll to a particular row or column documentation on how the scroll methods are expected to work.

    May I ask you to ensure you are testing with the latest version?
    In case you can still observe the problems you are reporting, would you please open a support thread and send us a demo solution to illustrate the issues?

    Regards,
    Didie
    Telerik
     

    Build cross-platform mobile apps using Visual Studio and .NET. Register for the online webinar on 03/27/2014, 11:00AM US ET.. Seats are limited.

     
Back to Top