This is a migrated thread and some comments may be shown as answers.

TreeListView, Virtualization and ScrollIntoViewAsync

3 Answers 99 Views
TreeListView
This is a migrated thread and some comments may be shown as answers.
Licenses
Top achievements
Rank 1
Licenses asked on 27 Mar 2014, 10:06 AM
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.}

3 Answers, 1 is accepted

Sort by
0
Licenses
Top achievements
Rank 1
answered on 27 Mar 2014, 10:09 AM
[quote]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.}
[/quote]

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

0
Licenses
Top achievements
Rank 1
answered on 27 Mar 2014, 12:04 PM
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
0
Dimitrina
Telerik team
answered on 01 Apr 2014, 10:23 AM
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.

 
Tags
TreeListView
Asked by
Licenses
Top achievements
Rank 1
Answers by
Licenses
Top achievements
Rank 1
Dimitrina
Telerik team
Share this question
or