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.63k stars 1.62k forks source link

CollectionView with GridItemsLayout: Items do not update from DataTemplate Bindings [Android] #22044

Open nshtinkov opened 2 weeks ago

nshtinkov commented 2 weeks ago

Description

In a CollectionView with a grid layout, certain elements do not update from the DataTemplate bindings. In the sample app this happens for the IsVisible property of a BoxView with binding to a view model property that is changed in response to a tap on the item.

This only happens in certain columns of the CollectionView and does not happen if the layout is a single-column list (Span=1). With two columns (Span=2) I see this only in the second column, while with 5 columns this happens for the 1st and 3rd columns (see screenshots below).

image image

The images are produced by starting the app and then tapping on each item only once. After tapping an item, it should be greyed out; however this only happens in certain columns. The number of tapped items is shown in the title bar (selected items count).

Items in the affected columns do not update only on the first change (first tap after the app start). On the third tap (which again makes the BoxView visible), the items are greyed out as expected.

Steps to Reproduce

  1. Start the repro app on emulator or physical device
  2. Tap each item on the screen once. After tapping, an item should become grey and the "selected items" count on top should increase by one.
  3. In some columns the items are not greyed out after tapping. However the "selected items" count is correctly updated, showing that tapping works and the IsSelected property of the view model has been updated.

Link to public reproduction project repository

https://github.com/nshtinkov/CollectionViewItemTappedBug.git

Version with bug

8.0.21 SR4.1

Is this a regression from previous behavior?

Not sure, did not test other versions

Last version that worked well

Unknown/Other

Affected platforms

Android

Affected platform versions

Android 13

Did you find any workaround?

No

Relevant log output

No response

nshtinkov commented 2 weeks ago

This could be related to #8135. The column dependence was not observed there; maybe the fix was tested only for a single-column list so the remaining issues avoided detection.

RoiChen001 commented 2 weeks ago

Can repro this issue at Android platform at the latest 17.10 Preview 5 (8.0.20&8.0.21).

MAUIoxo commented 2 weeks ago

Have a similar issue and yes, only on Android - any workarounds?

maonaoda commented 1 week ago

try to use this temporary CustomObservableCollection to replace ObservableCollection ;)

    public class CustomObservableCollection<T> : ObservableCollection<T>
    {
        public CustomObservableCollection()
        {
            CollectionChanged += CustomObservableCollection_CollectionChanged;
        }

        private void CustomObservableCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == NotifyCollectionChangedAction.Add)
            {
                foreach (T item in e.NewItems)
                {
                    SubscribeToItemPropertyChanged(item);
                }
            }
            else if (e.Action == NotifyCollectionChangedAction.Remove)
            {
                foreach (T item in e.OldItems)
                {
                    UnsubscribeFromItemPropertyChanged(item);
                }
            }
        }

        private void SubscribeToItemPropertyChanged(T item)
        {
            if (item != null && item is INotifyPropertyChanged notifyPropertyChangedItem)
            {
                notifyPropertyChangedItem.PropertyChanged += Item_PropertyChanged<T>;
            }
        }

        private void UnsubscribeFromItemPropertyChanged(T item)
        {
            if (item != null && item is INotifyPropertyChanged notifyPropertyChangedItem)
            {
                notifyPropertyChangedItem.PropertyChanged -= Item_PropertyChanged<T>;
            }
        }

        private void Item_PropertyChanged<T1>(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "IsSelected")
            {
                OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, sender, null, this.IndexOf((T)sender)));
            }
        }
    }

If you don't want flickering when rendering data changes, add this to further fix.

                .ConfigureMauiHandlers(x =>
                {
#if ANDROID
                    Microsoft.Maui.Handlers.ViewHandler.ViewMapper.AppendToMapping<CollectionView, CollectionViewHandler>(nameof(CollectionViewHandler.PlatformView), (h, v) =>
                    {
                        if (h.PlatformView?.GetItemAnimator() is DefaultItemAnimator itemAnimator)
                        {
                            itemAnimator.ChangeDuration = 0;
                        }
                    });
#endif
                })

https://github.com/dotnet/maui/assets/32831595/0aa47656-586d-49a5-89b6-003808733d7e

maonaoda commented 1 week ago

However, there is still a small probability that this will recur 。。。:0