unoplatform / uno

Open-source platform for building cross-platform native Mobile, Web, Desktop and Embedded apps quickly. Create rich, C#/XAML, single-codebase apps from any IDE. Hot Reload included! 90m+ NuGet Downloads!!
https://platform.uno
Apache License 2.0
9.09k stars 739 forks source link

[Android] GridView Doesn't Render image in 1st Item on Android with ObservableCollection #6400

Open SkyeHoefling opened 3 years ago

SkyeHoefling commented 3 years ago

Current behavior

When using an ObservableCollection with a GridView control the 1st item in the ItemsSource doesn't render images correctly when loaded sequentially. For example if you have a DataTemplate that displays an image and text the first one will just have the text where the remaining items will all render correctly with the image and text.

To the best of my knowledge this only happens with ObservableCollection<T> and doesn't happen if you update the entire ItemsSource at once.

Android Screenshot Notice in the screenshot below the first folder image is missing

image

UWP Rendering Notice all items are rendered correctly image

The code in question is loading data and adding 1 item at a time to the ObservableCollection<T>. This is a common practice when using ObservableCollection<T>.

public void LoadData()
{
    var data = new[] { "One", "Two", "Three", "Four", "Five", "Six", "Seve", "Eight", "Nine", "Ten", "Elevn", "Twelve", "Thirteen" }
        .Select(x => new Item { Name = x })
        .ToArray();

    Items.Clear();
    foreach (var item in data)
    {
        Items.Add(item);
    }
}

Expected behavior

I expect the Android platform to render the 1st item just like every other item with the folder image and the text below.

How to reproduce it (as minimally and precisely as possible)

I have attached a minimal project that reproduces this issue on Android

Workaround

My workaround is to not use an ObservableCollection<T> but to just a List<T> and when I'm done loading the data fire the INotifyPropertyChanged for the entire collection. This will update the entire collection of the ItemsSource on the GridView.

List<Item> myItems;
public List<Item> MyItems
{
  get => myItems;
  set => SetProperty(ref myItems, value);
}

public void LoadData()
{
    MyItems = new[] { "One", "Two", "Three", "Four", "Five", "Six", "Seve", "Eight", "Nine", "Ten", "Elevn", "Twelve", "Thirteen" }
        .Select(x => new Item { Name = x })
        .ToList();
}

Performance Considerations If you are working with a large data set and are adding 1 item at a time this isn't a good option as it will reload the entire GridView with every update. You may be able to use an ObservableCollection in this fashion for first load then do incremental changes, but I haven't tested it.

Works on UWP/WinUI

yes

Environment

Nuget Package:

Nuget Package Version(s): 3.8.11

Affected platform(s):

IDE:

Relevant plugins:

Anything else we need to know?

N/A

jeromelaban commented 3 years ago

Thanks for the report.

This could be an Image issue, not a ListView issue. What happens if you bind the image url to a textblock ? Does it appear ?

/cc @davidjohnoliver

SkyeHoefling commented 3 years ago

In the reproduction project I am not binding the image it is a hard-coded value for the source. See the DataTemplate below:

<DataTemplate x:Key="MyItemTemplate">
  <StackPanel Spacing="20" Width="175" Height="250">
    <Image Source="ms-appx:///Assets/Images/folder.png" />
    <TextBlock
      Text="{Binding Name}"
      HorizontalAlignment="Center"
      HorizontalTextAlignment="Center"
      TextWrapping="WrapWholeWords" />
  </StackPanel>
</DataTemplate>