ArgumentOutOfRangeException при удалении элемента из ListView с помощью RecycleElement в Xamarin Forms для Android - PullRequest
0 голосов
/ 02 августа 2020

У меня есть ListView, привязанный к списку на ViewModel. Моя модель довольно проста:

    public class Model : RealmObject
    {
        public string Name { get; set; }
    }

В представлении мало что происходит, но я добавил контекстное действие к ячейкам, привязанным к DeleteCommand:

<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Book.Views.MyPage"
             x:Name="page">
    <ContentPage.Content>
        <StackLayout>
            <ListView ItemsSource="{Binding Models}"
                      SelectionMode="Single"
                      CachingStrategy="RecycleElement">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <TextCell Text="{Binding Name}">
                            <TextCell.ContextActions>
                                <MenuItem Command="{Binding Path=BindingContext.DeleteCommand, Source={x:Reference page}}"
                                  CommandParameter="{Binding .}"
                                  Text="Delete" IsDestructive="True" />
                            </TextCell.ContextActions>
                        </TextCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

Затем у нас есть ViewModel

    public class MyViewModel : BaseViewModel
    {
        readonly Realm realm;
        public ICommand DeleteCommand { get; private set; }
        public IEnumerable<Model> Models { get; set; }

        public ContactsListViewModel()
        {
            realm = Realm.GetInstance();
            AddElements();
            Models = realm.All<Model>();
            DeleteCommand = new Command<Model>(Delete);
        }

        void AddElements() //For testing
        {
            for (int i = 0; i < 5; i++)
            {
                realm.Write(() =>
                {
                    var c = new Model()
                    {
                        Name = $"Name{i}"
                    };
                    realm.Add(c);
                });
            }
        }

        void Delete(Model model)
        {
            realm.Write(() =>
            {
                realm.Remove(model);
            });
        }
    }

Моя проблема в том, что я получаю ArgumentOutOfRangeException, как только пытаюсь что-то удалить. Трассировка стека выглядит следующим образом:

System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
Parameter name: index
  at Xamarin.Forms.ListProxy.get_Item (System.Int32 index) [0x0000b] in D:\a\1\s\Xamarin.Forms.Core\ListProxy.cs:129
  at Xamarin.Forms.ListProxy.System.Collections.IList.get_Item (System.Int32 index) [0x00000] in D:\a\1\s\Xamarin.Forms.Core\ListProxy.cs:443
  at Xamarin.Forms.Platform.Android.ListViewAdapter.GetDataTemplateForPath (System.Int32 indexPath) [0x00007] in D:\a\1\s\Xamarin.Forms.Platform.Android\Renderers\ListViewAdapter.cs:367
  at Xamarin.Forms.Platform.Android.ListViewAdapter.GetPrototypicalCell (System.Int32 indexPath) [0x00012] in D:\a\1\s\Xamarin.Forms.Platform.Android\Renderers\ListViewAdapter.cs:391
  at Xamarin.Forms.Platform.Android.ListViewAdapter.IsEnabled (System.Int32 position) [0x00023] in D:\a\1\s\Xamarin.Forms.Platform.Android\Renderers\ListViewAdapter.cs:427
  at Android.Widget.BaseAdapter.n_IsEnabled_I (System.IntPtr jnienv, System.IntPtr native__this, System.Int32 position) [0x00008] in <55654ebe9f2a48e6bade2862bb243f94>:0
  at at (wrapper dynamic-method) Android.Runtime.DynamicMethodNameCounter.72(intptr,intptr,int)

Это происходит только на Android, и этого не происходит, если я удалю CachingStrategy="RecycleElement" ИЛИ если я заключу содержимое Delete в Device.BeginInvokeOnMainThread . Последнее не имеет для меня особого смысла, поскольку Delete уже вызывается в потоке пользовательского интерфейса.

Учитывая, что происходит, я полагаю, что это может быть состояние гонки, но, возможно, кто-то может избавиться немного света на то, почему это происходит?

...