1

I've got the problem, that I create an App, that will run on Windows Phone 8.1 and Windows 10 Mobile. This App is a non-UWP Windows Store App. The problem I have is, that I have a list of a custom control that one has another List, that is not expanded (=collapsed). That looks like this: The red rectangles are the ContentPresenter items of the first ItemControl and the green rectangles are the ContentPresenter items of the ItemControl in the first lists items, that is not visible on startup. It will be visible after the click on the expand-button. Both ItemControls have a DataTemplate configured to present what you see in the screenshot. (XAML code below)

The main problem I have is, that if I change the Pivot to the Pivot you see at the screenshot above, there is a freeze of the app for several seconds. It depends on the device how long this freeze is. In the W10M-Emulator on my PC I don't recognize a freeze but on a Lumia 620 with WP8.1 I have a freeze of 8.5 seconds. In the profiler of Visual Studio it looks like this (I selected the range that is the problem I am talking about): enter image description here

What I am wondering about is the large orange line with "Layout". If I expand it to the "big players", there is 60-70ms for each not visible item in the profiler.

a I am asking myself why this is the case, even if the items are not visible and are in the VirtualizingStackPanel. The Number of Items of the ItemSourcein this example is 3 for the first ItemControl (red boxes) and 17, 59 and 1 for the second ItemControls that are only visible of the first item is expanded.

What I am also wondering about is, that regarding the timeline, all of the Items are processed at the same time because their baseline is for all items the same. But if I scroll down the profiler timeline details, I see another Event called "Parsing" for each item. That one is not processed in parallel for each item but serial. And the parsing of the last item fits to the end of the layout-event. This parsing events look like this:enter image description here What is the reason why the parsing takes so long time? I don't think that the controls are very complex etc. and there are no code behind procedures except some string formattings.

Finally here is the XAML code: My PivotItem on the "MainPage" of the App:

<PivotItem 
    Header="Echtzeit"
    Margin="10,-20,10,0"
    >
    <Grid>
        <ScrollViewer 
            VerticalScrollBarVisibility="Visible"
            >
            <ItemsControl
                ItemsSource="{Binding RealtimeDepartures, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
                HorizontalAlignment="Stretch"
                Margin="0"
                >
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <VirtualizingStackPanel />
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <controls:RealtimeStation
                                StationName="{Binding StationName, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
                                Departures="{Binding DepartureList, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
                                FontSize="{Binding DataContext.ClientFontSize, ElementName=MainPg, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
                                />
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </ScrollViewer>
    </Grid>                
</PivotItem>

The RealtimeStation Control XAML:

<UserControl
    ...
    >

    <UserControl.Resources>
        <dec:BoolToVisibilityConverter x:Key="BoolToVisibilityConv"/>
    </UserControl.Resources>

    <Grid>
        <AppBarButton
            HorizontalAlignment="Left"             
            VerticalAlignment="Top"
            Grid.Column="0"
            Name="btnExpand"            
            Icon="{Binding ExpandButtonIcon, ElementName=main, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
            Click="btnExpand_Click"
            IsEnabled="{Binding IsExpandButtonEnabled, ElementName=main, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
            IsCompact="True"
            Margin="0,-8,-2,-4"
            />

        <StackPanel
            Orientation="Vertical"
            Margin="48,12,0,0"
            >            
            <TextBlock 
                Text="{Binding StationName, ElementName=main, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}" 
                VerticalAlignment="Center"
                FontSize="24"               
                />

            <TextBlock
                Text="Derzeit stehen keine Abfahrten an"
                FontStyle="Italic"
                Visibility="{Binding ShowNoDepartures, ElementName=main, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
                FontSize="{Binding FontSize, ElementName=main, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
                />

            <TextBlock
                Text="Zugausfälle vorhanden!"
                Foreground="Red"
                FontWeight="Bold"
                Visibility="{Binding ShowTrainCanceled, ElementName=main, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
                FontSize="{Binding FontSize, ElementName=main, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
                />

            <ItemsControl
                ItemsSource="{Binding DepartureList, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
                ScrollViewer.VerticalScrollBarVisibility="Visible"
                ScrollViewer.HorizontalScrollBarVisibility="Disabled"
                Margin="-48,0,0,0"
                Visibility="{Binding IsExpanded, ElementName=main, UpdateSourceTrigger=PropertyChanged, Mode=OneWay, Converter={StaticResource BoolToVisibilityConv}}"
                >
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <VirtualizingStackPanel />
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <ContentPresenter>
                            <controls:RealtimeDeparture
                                DepartureDetails="{Binding}"
                                FontSize="{Binding FontSize, ElementName=main, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
                                />
                        </ContentPresenter>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </StackPanel>
    </Grid>
</UserControl>

And finally the RealtimeDeparture Control:

<UserControl
    ...
    >
    <Grid>
        <control:DisruptionIcon
            Height="24"
            Width="50"
            HorizontalAlignment="Left"
            VerticalAlignment="Top"
            Icon="{Binding TrainIcon, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
            Margin="3"
            />

        <StackPanel 
            Orientation="Vertical"
            Margin="56,9,0,0"
            >
            <StackPanel
                Orientation="Horizontal"
                Margin="3,0"
                VerticalAlignment="Center"
                >

                <TextBlock
                    Text="{Binding DelayTimeText, ElementName=main, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
                    Foreground="{Binding DelayColor, ElementName=main, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
                    />
                <TextBlock
                    Text="{Binding DepartureDetailsText, ElementName=main, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
                    Margin="3,0"
                    />
            </StackPanel>

            <TextBlock
                Text="{Binding InformationText, UpdateSourceTrigger=PropertyChanged, Mode=OneWay, ElementName=main}"
                Visibility="{Binding IsInformationVisible, UpdateSourceTrigger=PropertyChanged, Mode=OneWay, ElementName=main}"
                Margin="3"
                FontStyle="Italic"
                TextWrapping="Wrap"
                />
            <TextBlock 
                Text="Zug fällt aus!"
                Foreground="Red"
                FontWeight="Bold"
                Visibility="{Binding IsCanceledVisible, UpdateSourceTrigger=PropertyChanged, Mode=OneWay, ElementName=main}"
                Margin="3"
                />
        </StackPanel>
    </Grid>    
</UserControl>

Does anybody has an idea how to speed up this parsing? What is the reason why it is so slow? Do I have a design issue that is disabling the virtualization-functionality of the VirtualizedStackPanel? I already tried a lot but didn't find the reason why it is so slow.

Hunv
  • 385
  • 7
  • 17
  • Ya there's a lot to be said about this but it's a pretty broad question requiring a broad answer that may not be the best suited for this site. You'll need to do proper layout with less panels to include for instance use of a date template selector instead of these nested itemscontrols, and provide an boundary to invoke virtualization which itemscontrol doesn't have scrollviewer built in. For reference here's a wpf answer but a full answer would require a rewrite, sorry. [for ref](http://stackoverflow.com/questions/2783845/virtualizing-an-itemscontrol) – Chris W. May 01 '17 at 21:17
  • Hi @ChrisW., I already did most of the things in your ref. `CanContentScroll` is no property available in Windows Store Apps btw.. But I also tried it with `ListView`s and `ListBoxe`s instead of the `ItemsControl` and read this article without any luck - it even felt worse than before: https://msdn.microsoft.com/en-us/library/vstudio/cc716879(v=vs.100).aspx – Hunv May 02 '17 at 18:21
  • Additional info: Checked it with current data: ListView vs ItemsControl (without ScrollViewer) = `ListView` 12sec vs `ItemsControl` 7sec. So the theoretically "optimized" control is much slower than the not "optimized" one (regarding my link) – Hunv May 02 '17 at 18:33
  • Ya there's a lot more to ListView/ListBox than there is to ItemsControl since they come with a lot more built into the default base templates. ItemsControl literally just repeated whatever you have as Item Template while the other two include actions, states, etc per item and present them differently. However if virtualization is in fact being invoked than it should make the greatest difference by far. – Chris W. May 02 '17 at 18:42
  • Have a similar problem. Your Problem seems to be that the virtualization isn't used b/c all subitems are nested in each other and thus need to be calculated for layout. As Chris pointed out, you should replace that nesting with something flatter, i.e. data templates. Did you solve it in the end? (it's 4 years later...) – MHolzmayr Jun 17 '21 at 08:17

1 Answers1

0

I don't think virtualization is turned on. Try setting the CanContentScroll property to true on your ScrollViewer:

<ScrollViewer
    CanContentScroll="true"
    VerticalScrollBarVisibility="Visible"
>

The other option can be using e.g. ListBox which supports virtualization on its own (as far as I know it is enough to set the ItemsPanelTemplate to VirtualizingStackPanel)