Search code examples
uwpwebassemblyuno-platform

Behavior of ObservableCollection is different on UWP and WASM


I have a uno app where the observableCollection behaves differently on UWP and WASM platforms.

It occurs in a GridView with an ItemsWrapGrid specifed as the itemsPanel. The ItemSource is an ObservableCollection. This is the xaml:

<GridView x:Name="gView" ItemsSource="{Binding Pictures,Mode=OneWay}" SelectionMode="Extended" IsMultiSelectCheckBoxEnabled="False" 
          VerticalAlignment="Stretch" HorizontalAlignment="Center" SelectionChanged="ImageSelectionChanged" >
    <GridView.ItemContainerStyle>
        <Style TargetType="GridViewItem">
            <Setter Property="Margin" Value="10"/>
        </Style>
    </GridView.ItemContainerStyle>
    <GridView.ItemsPanel>
        <ItemsPanelTemplate>
            <not_wasm:ItemsWrapGrid Orientation="Horizontal"  MaximumRowsOrColumns="8"/>
            <wasm:WrapPanel/>
        </ItemsPanelTemplate>
    </GridView.ItemsPanel>
    <GridView.ItemTemplate>
        <DataTemplate>
            <Grid Margin="4">
                <Image Source="{Binding URL}" Width="{Binding Parent.ImageWidth, Mode=TwoWay}" MinWidth="200"/>
                <TextBlock Text="{Binding PictureKey}" Foreground="Yellow" FontSize="14" HorizontalAlignment="Center"
                           VerticalAlignment="Bottom" Margin="0,0,10,0"/>
            </Grid>
        </DataTemplate>
    </GridView.ItemTemplate>
</GridView>

The user is allows to select items and remove them from the view. This is the relevant code:

if (result == 1)
{
    int ndx = vm.EvtViewModel.Pictures.IndexOf(pict);
    vm.EvtViewModel.Pictures.Remove(pict);
    if (ndx < vm.EvtViewModel.Pictures.Count)
    {
        vm.EvtViewModel.SelectedPicture = vm.EvtViewModel.Pictures[ndx];
    }
    else
    {
        vm.EvtViewModel.SelectedPicture = vm.EvtViewModel.Pictures.Count > 0 ? vm.EvtViewModel.Pictures.Last() : null;
    }
}

where vm.EvtViewModel.Pictures is the ObservableCollection. The issue is that on UWP the items are removed and the remaining items below them are moved up the list. On WASM, it triggers a complete redraw of the Grid.

Is there a way to fix this?


Solution

  • There's no easy fix for this, but it'll be partially addressed in an upcoming Uno version. To understand the issue, note that you're using WrapPanel on WebAssembly and ItemsWrapGrid on UWP, which is the recommended approach since ItemsWrapGrid isn't yet implemented for WASM.

    WrapPanel is a 'non-virtualizing' panel, meaning it eagerly creates views for all items in the items source. At present, non-virtualizing panels are not optimized for use with ObservableCollection on WASM. This will be addressed by this change, which will prevent the entire grid being redrawn when a single item is inserted.