Scrolling entire elements problem

8 posts, 0 answers
  1. M L
    M L avatar
    16 posts
    Member since:
    May 2010

    Posted 25 Jul 2014 Link to this post

    Hello,
    We're using RadListbox to display elements of varying height. Some of them are small, some are large.
    The default behaviour of the scroll mechanism seems to work based on the whole items.
    For example if the user clicks with his mouse on the up or down arrow of the scrollbar (vertical one) he gets shifted by the length of the visible item. Gets shifted more for bigger items.
    Also, when doing

    var v = radlistboxChat.ChildrenOfType<ScrollViewer>();
    foreach (var q in v)
    {
       q.ScrollToBottom();
    }

    to programatically scroll down to the last item, often we observe that in case of larger items, the item gets positioned at the top of the RadListbox, leaving an empty space below. My guess is that it happens because the previous item is also big, and if this was to scroll to the bottom, it would show the last element at the bottom but the previous element would not fit the remaining space and would need to be displayed partially, which the listbox doesnt want to do.

    We found a simple solution to the problem. We do something like this:

    <ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
        <telerik:RadListBox ScrollViewer.VerticalScrollBarVisibility="Disabled" >
    </ScrollViewer>

    This puts the listbox into a scrollviewer that works as expected. It operates on pixel lenghts rather than item height's, so the scrolling is smooth and scrolltobottom works as expected.
    However, there is a very weird behaviour observed with this solution.
    Populating items and refreshing the listbox becomes significantly longer. An average sized list of items refreshed in 90 ms without the additional scrollviewer, but it took 1800 ms to do the same with the scrollviewer, That's 20 times longer. Our requirements indicate that our list needs to refresh quickly, since its often refreshed.

    My question to you is:
    Can I make the scrollbar of the listbox behave like in our solution while and maintain it's original speed?
    thanks.
  2. Kalin
    Admin
    Kalin avatar
    1207 posts

    Posted 28 Jul 2014 Link to this post

    Hello,

    Indeed the explained behavior is caused by the different Heights of the ListBoxItems - a single item is always scrolled to top of the ListBox. However what I can suggest you in order to align the last item to the bottom of the ListBox, would be to set the ScrollViewer.CanContentScroll attached property to False. This way the ListBox will be scrolling by pixels not by item. Please test it and let me know if this helps.

    Hope it will work for you.

    Regards,
    Kalin
    Telerik
     
    Check out Telerik Analytics, the service which allows developers to discover app usage patterns, analyze user data, log exceptions, solve problems and profile application performance at run time. Watch the videos and start improving your app based on facts, not hunches.
     
  3. UI for WPF is Visual Studio 2017 Ready
  4. M L
    M L avatar
    16 posts
    Member since:
    May 2010

    Posted 28 Jul 2014 in reply to Kalin Link to this post

    Hello,
    thank you for your answer.
    The property does indeed behave as we want. However the behaviour is identical to the one posted in my first post.
    Which means the scrolling works in a pixel based way, but refreshing the listbox items takes a much longer time.

    We're making a simple chat program for the use of our employees.
    We display chat messages as items (with a template) inside a RadListBox.
    Everytime a new message arrives we attach new source with the updated list of messages.

    radlistboxChat.ItemsSource = messages;

    With the default value for ScrollViewer.CanContentScroll we observe the listbox to refresh instantenously. But with the flag changed to false, the refresh gets significatly slower, freezing the GUI as well.

    I've quickly prepared an example. I'll copy here the important parts, I hope it's enough.

    First, an important observation: this seems to be affected by the itemtemplate. The more complex the template the bigger difference in speed between both scrolling modes.
    For testing I made a simple template:

    <DataTemplate x:Key="TestTemplate">
            <Grid Margin="2 0">
                <Grid.RowDefinitions>
                    <RowDefinition Height="50"/>
                    <RowDefinition Height="50"/>
                </Grid.RowDefinitions>
                <TextBlock Grid.Row="0" Text="{Binding Name}" TextWrapping="Wrap"/>
                <TextBlock Grid.Row="1" Text="{Binding Status}" TextWrapping="Wrap"/>
            </Grid>
        </DataTemplate>

    Next, in XAML I got a radlistbox defined as follows:

    <telerik:RadListBox Name="radlistboxChat"  ScrollViewer.CanContentScroll="True" HorizontalContentAlignment="Left" ItemTemplate="{StaticResource TestTemplate}">
                        
    </telerik:RadListBox>

    Now, I've made a test button to populate the items with the following code behind.

    private void radbuttonTest_Click(object sender, RoutedEventArgs e)
            {
                List<TestTemplateClass> items = new List<TestTemplateClass>();
                for (int i = 0; i < 5000; ++i)
                {
                    TestTemplateClass item = new TestTemplateClass();
                    item.Name = "test";
                    item.Status = "test";
                    items.Add(item);
                }
                radlistboxChat.ItemsSource = items;
                radlistboxChat.UpdateLayout();
                var v = radlistboxChat.ChildrenOfType<ScrollViewer>();
                foreach (var q in v)
                {
                    q.ScrollToBottom();
                }
            }
            public class TestTemplateClass
            {
                public string Name { get; set; }
                public string Status { get; set; }
            }

    Please check the above simple example. If you run it as it is - your list will be populated fast, but will have the scrolling by item height problem.
    Next, please change the ScrollViewer.CanContentScroll="True" to False and run the application again.
    Now, the scrolling works, but you should notice a very long wait for the ListBox to display items.
    So, this is still a problem for us.
  5. M L
    M L avatar
    16 posts
    Member since:
    May 2010

    Posted 28 Jul 2014 Link to this post

    Oh, and 5000 in the loop may seem like a lot, but since our itemtemplate is more complex, the actual number of items displayed before we notice a slowdown is much much smaller, making optimizations based on number of displayed items not really possible.
  6. Kalin
    Admin
    Kalin avatar
    1207 posts

    Posted 28 Jul 2014 Link to this post

    Hi,

    I understand you concern. However could you please share some more details about the exact requirements for the chat implementation? Do you really need to have selection there, as if not you could use a simple ItemsControl instead of the ListBox?

    Also what I can suggest you would be not to replace the whole ItemsSource every time you add items, but use ObesrvableCollection instead and simply add the items to it. The ObservableCollection will notify the UI and the new items will show up. Afterwards you can simply scroll to the last one using the ListBox ScrollIntoView method.

    I'm looking forward to your response.

    Regards,
    Kalin
    Telerik
     
    Check out Telerik Analytics, the service which allows developers to discover app usage patterns, analyze user data, log exceptions, solve problems and profile application performance at run time. Watch the videos and start improving your app based on facts, not hunches.
     
  7. M L
    M L avatar
    16 posts
    Member since:
    May 2010

    Posted 28 Jul 2014 Link to this post

    That means, this behaviour is expected? That a change to scrolling method changes the refresh rate dramatically?
    I assumed it to be a bug of some sorts.

    We can look into other controls, but we're using selection for being able to select a few messages we wish to copy into clipboard.
    I can also check the ObservableCollection. However I suspect it will improve the responsivnes in case of new messages, but not fix the problem entirely. For example when we select a different user in our chat program, we load the last history of the chat between both users. This would mean selecting a new user for the first time would still freeze the GUI.
  8. M L
    M L avatar
    16 posts
    Member since:
    May 2010

    Posted 29 Jul 2014 Link to this post

    Any solution to this using a radlistbox?
    Picking a different control is not a straight forward process right now, since we use the selectedItems property.
  9. Kalin
    Admin
    Kalin avatar
    1207 posts

    Posted 30 Jul 2014 Link to this post

    Hi,

    I'm afraid that currently these are the possible solutions for this scenario. Did you try the approach with the ObservableCollection and how did it work? You can also try using ListBoxPanel as ItemsPanel of the ListBox:

    <telerik:RadListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <telerik:ListBoxPanel />
        </ItemsPanelTemplate>
    </telerik:RadListBox.ItemsPanel>

    Let me know how it works for you.

    Hope this helps.

    Regards,
    Kalin
    Telerik
     
    Check out Telerik Analytics, the service which allows developers to discover app usage patterns, analyze user data, log exceptions, solve problems and profile application performance at run time. Watch the videos and start improving your app based on facts, not hunches.
     
Back to Top
UI for WPF is Visual Studio 2017 Ready