Search code examples
c#windows-phone-8scrolllonglistselector

Performance lag in scrollTo function for LongListSelector in WP8?


To demonstrate the problem here is my code behind code

public partial class MainPage : PhoneApplicationPage
{
    ObservableCollection<ABC> listTest = new ObservableCollection<ABC>();
    // Constructor
    public MainPage()
    {
        InitializeComponent();

        for (int i = 0; i < 50; i++)
        {
            ABC conv = new ABC(string.Format("Test:{0}", i));
            listTest.Add(conv);
        }
        testLls.ItemsSource = listTest;
    }

    private void Button_Tap_1(object sender, System.Windows.Input.GestureEventArgs e)
    {
        testLls.ScrollTo(listTest[listTest.Count - 1]);
    }

    private void TitlePanel_Tap_1(object sender, System.Windows.Input.GestureEventArgs e)
    {
        Stopwatch st = Stopwatch.StartNew();

        testLls.ScrollTo(listTest[listTest.Count - 1]);
        st.Stop();
        Debug.WriteLine("tttt:", st.ElapsedMilliseconds);
    }

    class ABC
    {
        private string _name;

        public ABC(string aa)
        {
            this._name = aa;
        }

        public string Name
        {
            get
            {
                return _name;
            }
        }

        public Visibility GroupMemberVisibility
        {
            get
            {
                return Visibility.Collapsed;
            }
        }
    }
}

Xaml Code

     <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28" Tap="TitlePanel_Tap_1">
        <TextBlock Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/>
        <TextBlock Text="page name" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
    </StackPanel>

    <!--ContentPanel - place additional content here-->
    <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
        <phone:LongListSelector Name="testLls" VirtualizingStackPanel.VirtualizationMode="Standard" >
            <phone:LongListSelector.ItemTemplate>
                <DataTemplate x:Name="dtRecievedBubbleText" >
                    <Grid x:Name="LayoutRoot" Background="Transparent" Margin="24 0 0 14"  HorizontalAlignment="Left">

                        <Grid.RowDefinitions>
                            <RowDefinition Height="14" />
                            <RowDefinition Height="Auto" />
                        </Grid.RowDefinitions>
                        <Grid Grid.Row="1">
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto" />
                                <RowDefinition Height="Auto" />
                                <RowDefinition Height="Auto" />
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto"/>
                            </Grid.ColumnDefinitions>
                            <Rectangle Grid.RowSpan="3" Fill="{Binding BubbleBackGroundColor}" />
                            <TextBlock Text="test" Visibility="{Binding GroupMemberVisibility}" FontSize="22" FontFamily="Segoe WP Semibold" Margin="12, 12, 0, 0"  />
                            <TextBlock Grid.Row="2" Text="{Binding Name}" HorizontalAlignment="Right" Margin="0,0,12,6" FontSize="18" />
                        </Grid>
                    </Grid>
                </DataTemplate>
            </phone:LongListSelector.ItemTemplate>
        </phone:LongListSelector>

    </Grid>

On tapping the header the long list selector containg the elemnts scrolls to bottom. When value of elements is changed from 30-50-100 elements the time observed is 20ms, 744ms, 815ms. The testing was done with a Nokia Lumia 620.

In this sample, the item template was very simple but in real scenario my item templates are much more complex. And thus the time taken in that scenario is 1753ms for 100 elements.

Why such a huge time difference. Can this be improved in any way?

Has anybody else observed this?


Solution

  • There is a workaround to fix this issue.

    Extract viewport from lls and then set viewport origin.

    To extract viewport we have to add style in xaml

      <Style x:Name="llsMessagesStyle"  TargetType="phone:LongListSelector">
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="phone:LongListSelector">
                        <Grid Background="{TemplateBinding Background}" d:DesignWidth="480" d:DesignHeight="800">
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="ScrollStates">
                                    <VisualStateGroup.Transitions>
                                        <VisualTransition GeneratedDuration="00:00:00.5"/>
                                    </VisualStateGroup.Transitions>
                                    <VisualState x:Name="Scrolling">
                                        <Storyboard>
                                            <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="VerticalScrollBar"/>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="NotScrolling"/>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                            <Grid Margin="0">
                                <ViewportControl x:Name="ViewportControl" HorizontalContentAlignment="Stretch" VerticalAlignment="Bottom" Loaded="ViewPortLoaded"/>
                                <ScrollBar x:Name="VerticalScrollBar" Style="{StaticResource ChatThemeScrollBarStyle}" Opacity="0" Margin="2 0 2 0" Orientation="Vertical" HorizontalAlignment="Right" Width="5" ValueChanged="vScrollBar1_ValueChanged"  />
                            </Grid>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    

    In code behind:

     ViewportControl llsViewPort;
        private void ViewPortLoaded(object sender, RoutedEventArgs e)
        {
            llsViewPort = sender as ViewportControl;
        }
    
     private void ScrollToBottom()
        {
            if (llsViewPort != null)
                llsViewPort.SetViewportOrigin(new System.Windows.Point(0, llsViewPort.Bounds.Height));
        }
    

    In this way we can achieve desired functionality.