dotnet / maui

.NET MAUI is the .NET Multi-platform App UI, a framework for building native device applications spanning mobile, tablet, and desktop.
https://dot.net/maui
MIT License
21.98k stars 1.71k forks source link

Icons showing up in the wrong places when using StreamImageSource as a source for images inside a CollectionView #23240

Open Leonardo-pixel opened 2 months ago

Leonardo-pixel commented 2 months ago

Description

We experienced some weird behavior when using a CollectionView to display items with a couple icons. When scrolling through the CollectionView, we noticed some of the icons where displayed in the wrong place. For example, some icons were shown in locations that shouldn't display an icon at all. We found out that this behavior only occurred on Android, when using a StreamImageSource. We weren't able to reproduce this issue on iOS and Windows, or when using a FileImageSource.

To make sure this wasn't because of our implementation, we managed to reproduce the issue in a simple Maui application, a linkt to this project is added below.

This is how it works: We have a single page consisting of the CollectionView with a DataTemplate containing a couple labels and images:

<CollectionView ItemsSource="{Binding Items}" BackgroundColor="White">
    <CollectionView.ItemTemplate>
        <DataTemplate>
            <Grid RowSpacing="0" Padding="12">
                <Grid.GestureRecognizers>
                    <TapGestureRecognizer Command="{Binding ItemTappedCommand, Source={x:Reference Page}}" CommandParameter="{Binding .}" />
                </Grid.GestureRecognizers>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>
                <Label Text="{Binding Name}" LineBreakMode="WordWrap" TextColor="Black"/>
                <StackLayout Grid.Row="2" Orientation="Horizontal">
                    <Label HorizontalOptions="StartAndExpand" Text="{Binding Description}" LineBreakMode="WordWrap" TextColor="Black"/>
                    <my:Image HorizontalOptions="End" CustomImageSource="{Binding ImageSource1}" WidthRequest="16" HeightRequest="16"/>
                    <my:Image HorizontalOptions="End" CustomImageSource="{Binding ImageSource2}" WidthRequest="16" HeightRequest="16"/>
                    <my:Image HorizontalOptions="End" CustomImageSource="{Binding ImageSource3}" WidthRequest="16" HeightRequest="16"/>
                </StackLayout>
            </Grid>
        </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>

The GestureRecognizer is to verify whether the tapped item should display a third icon or not. The item that we are displaying is a simple object with a name, description and three file names. These file names are all strings and are used in the custom image control to load the image via a stream.

When the value of the CustomImageSource property is changed a task is queued to update the Source property of the image. This queue is added to make sure the sequence of tasks is always correct (we want to rule out that the issue we're having is due to timing). It is, however, still possible (maybe even easier) to reproduce this issue when not utilizing the queue. This is how we retrieve the image and update the Source:

private async Task SetImageAsync(string imageSource, int instanceNumber)
{
    await Dispatcher.DispatchAsync(() => Source = null);
    if (string.IsNullOrEmpty(imageSource))
    {
        return;
    }

    // Loading images from stream has an issue when used in a collection view.
    // Make sure the test_icon* files have the right build action (Embedded resource).
    // Await makes it easier to reproduce the issue.
    await Task.Delay(1000);
    var assembly = Assembly.GetExecutingAssembly();
    Stream? stream = assembly.GetManifestResourceStream($"IconsTestApp.Resources.Images.{imageSource}");
    if (stream == null)
    {
        return;
    }
    ImageSource streamImageSource = ImageSource.FromStream(() => stream);

    //Loading image from file doesn't have the issue.
    // Make sure the test_icon* files have the right build action (Maui image).
    //ImageSource fileImageSource = ImageSource.FromFile(imageSource);

    await Dispatcher.DispatchAsync(() => Source = streamImageSource);
}

The await is used to make it easier to reproduce the issue. When the source is updated fast enough, this becomes much harder. Below is a recording of the issue (notice how the first three items shouldn't have a third icon):

https://github.com/dotnet/maui/assets/51745898/7c0aa22c-196d-4fd7-b03a-e2294a2d2ab3

We're fairly certain this issue is a result of using a StreamImageSource in combination with the recycling mechanism of the CollectionView. I'd also like to point out that this did work when we were still using Xamarin, we did however use the FFImageLoading library so that might have been the reason the issue wasn't present when using Xamarin. Finally, at the time of writing we are using version 8.0.60, but this issue was also present in previous versions (we haven't tested all of them).

Steps to Reproduce

  1. Install the linked project.
  2. Start the project (on an Android device/emulator).
  3. Scroll down the list of items as fast as possible.
  4. Scroll up again.
  5. Most likely some items display a third icon, even though they shouldn't.

Link to public reproduction project repository

https://github.com/Leonardo-pixel/IconsTestApp

Version with bug

8.0.60 SR6

Is this a regression from previous behavior?

Yes, this used to work in Xamarin.Forms

Last version that worked well

Unknown/Other

Affected platforms

Android

Affected platform versions

No response

Did you find any workaround?

A work-around could be to use a FileImageSource instead, however in our actual application, we download the icons we want to display and having to convert these to a FileImageSource would result in a (probably big) performance hit.

Relevant log output

No response

github-actions[bot] commented 2 months ago

Hi I'm an AI powered bot that finds similar issues based off the issue title.

Please view the issues below to see if they solve your problem, and if the issue describes your problem please consider closing this one and thumbs upping the other issue to help us prioritize it. Thank you!

Open similar issues:

Closed similar issues:

Note: You can give me feedback by thumbs upping or thumbs downing this comment.

kevinxufei commented 2 months ago

Verified this issue with Visual Studio 17.11.0 Preview 2.1 (8.0.60 & 8.0.40 & 8.0.10). Can repro this issue. IconsTestApp-main.zip