locked
How to try and troubleshoot UI lockup?

    Question

  • I have an app where, in a given test case, a GridView is being populated with up to 26 groups of up to 12 items in each group. The template used for these items initially displays a static graphic but then kicks off a background activity to see if there is a photo associated with the item to display instead.

    The problem I'm having is that even though I'm using Task.Run to run the background activity, the UI remains unresponsive pretty much until the background activity has finished.

    Someone has suggested that Image controls can stall the UI thread. Is that true and, if it is, is there anything I can do to alleviate that problem?

    Any other suggestions on what I can do to try to figure out why or where the UI thread is getting stalled?

    Thanks.

    Wednesday, March 18, 2015 9:08 AM

Answers

  • It looks as if, in my particular case, the problem was being caused by the use of StackPanel as the ItemsPanelTemplate for GridView. StackPanel disables virtualisation which caused all of the elements - and all of the associated background work - to be done at once.

    Switching to ItemsWrapGrid restores virtualisation and spreads out the background workload.

    The reason I was using StackPanel was due to a problem I experienced when writing the app for Windows 8.0 and the changing size of the horizontal scroll bar as you scrolled with other panel types. This seems to have been fixed in Win8.1

    • Marked as answer by Philip Colmer Tuesday, March 24, 2015 10:49 AM
    Tuesday, March 24, 2015 10:49 AM

All replies

  • Post the code. It's impossible to know what is happening without the code.


    I'm a self-taught noob amateur. Please take this into account when responding to my posts or when taking advice from me.

    Wednesday, March 18, 2015 11:11 AM
  • I can't post the code because in order to provide enough context would result in a LOT of code to wade through, particularly since SQLite is involved and I'd then have to provide enough code to allow adding data to the code and by the time I get to the end, I'm posting the source code to the entire app.

    I do understand that it is difficult to help without better understanding the code itself but that is why I was asking for suggestions on how to approach debugging a stalled UI thread ... as a general principle.

    Thanks.

    Wednesday, March 18, 2015 11:14 AM
  • Hi Philip,

    I'm wondering how you update the image to the front UI, let's say if we download the image to the memory and show the image to the UI should not cause the UI frozen, you binding the image to the UI or directly display the image var code ?

    --James


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.


    Friday, March 20, 2015 7:43 AM
    Moderator
  • Hi James

    In this particular situation, there isn't actually an image being loaded. What happens is that the GridView gets populated with a number of instances of this:

        <DataTemplate x:Key="Group80ItemTemplate">
            <Grid Margin="6" Width="240" HorizontalAlignment="Left">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <Border Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}" Width="60" Height="60" Visibility="{Binding ImageIsAvailable, Converter={StaticResource HideIfTrue}}">
                    <Grid>
                        <Button HorizontalAlignment="Left" VerticalAlignment="Top" Margin="5,5,0,0" Style="{StaticResource UnstyledGraphicsButtonStyle}" Width="{Binding ImageWidth50}" Height="{Binding ImageHeight50}" Foreground="white" Padding="0" Background="Transparent" BorderBrush="{x:Null}" IsEnabled="False">
                            <Button.ContentTemplate>
                                <DataTemplate>
                                    <Viewbox>
                                        <Path Width="{Binding ImageWidth50}" Height="{Binding ImageHeight50}"
                                                Stretch="Uniform" Fill="white"
                                                Data="{Binding ImageContent}"/>
                                    </Viewbox>
                                </DataTemplate>
                            </Button.ContentTemplate>
                        </Button>
                        <ProgressBar IsIndeterminate="{Binding FetchingImage}" Height="6" Width="60" VerticalAlignment="Bottom" Visibility="{Binding FetchingImage, Converter={StaticResource DisplayIfTrue}}"/>
                    </Grid>
                </Border>
                <Border Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}" Width="60" Height="60" Visibility="{Binding ImageIsAvailable, Converter={StaticResource DisplayIfTrue}}">
                    <Image DataContext="{Binding ImageObject}" Source="{Binding Image}" Stretch="UniformToFill" HorizontalAlignment="Center" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5">
                        <Image.RenderTransform>
                            <CompositeTransform Rotation="{Binding Rotation}"/>
                        </Image.RenderTransform>
                    </Image>
                </Border>
                <StackPanel Grid.Column="1" Margin="10,0,0,0" HorizontalAlignment="Stretch">
                    <TextBlock Text="{Binding Title}" Style="{StaticResource GroupItemTextStyle}" MaxHeight="40" TextWrapping="WrapWholeWords"/>
                    <TextBlock Text="{Binding Subtitle}" Style="{StaticResource CaptionTextBlockStyle}" TextWrapping="NoWrap"/>
                </StackPanel>
            </Grid>
        </DataTemplate>

    XAML then binds to ImageObject which is null initially if we don't have an image (ImageIsAvailable is false so this section is actually collapsed). The call to the ImageObject getter causes the related object to be added to a queue that is then processed via a worker task in order to query the database to see if there is an associated image record and, if there is, whether or not we have a file to go with it. IF the various bits and pieces come together so that we do have an image, the various properties change so that XAML is then triggered into querying ImageIsAvailable, ImageObject and Image all over again in order to then display the image.

    However, as I say, in this particular test that I'm running, NONE of the objects have any images so although the initial XAML call to ImageObject will trigger that worker task to process the queue, XAML doesn't update again. My concern is that it would *appear* that the UI thread stops responding (e.g. to sideways swipes on the screen) until the queue has been completely processed. I've managed to alleviate the problem slightly by gradually adding objects to the GridView (I was initially building the groups in a single Task and then adding them as the source to the GridView in one go) but I don't seem to be able to completely eliminate the problem.

    Someone on StackOverflow suggested that the Image control itself can cause a slight UI lockup but I'm not sure if that is the cause here given that I'm never giving the control anything to display.

    What I'm struggling to understand is how the worker task is causing the UI thread to lock up. It doesn't seem to be CPU as analysis shows the app doesn't take 100% CPU. If I had to guess, it would seem that XAML is calling something in my code that simply isn't returning but I'm not sure what that could be. Part of the challenge I have is that the more debugging statements I add, the slower the code runs (because of all of the Debug.WriteLine statements) so it actually becomes harder to figure out the code flow.

    Friday, March 20, 2015 2:51 PM
  • It looks as if, in my particular case, the problem was being caused by the use of StackPanel as the ItemsPanelTemplate for GridView. StackPanel disables virtualisation which caused all of the elements - and all of the associated background work - to be done at once.

    Switching to ItemsWrapGrid restores virtualisation and spreads out the background workload.

    The reason I was using StackPanel was due to a problem I experienced when writing the app for Windows 8.0 and the changing size of the horizontal scroll bar as you scrolled with other panel types. This seems to have been fixed in Win8.1

    • Marked as answer by Philip Colmer Tuesday, March 24, 2015 10:49 AM
    Tuesday, March 24, 2015 10:49 AM