Quantcast
Channel: Recent Threads — Xamarin Community Forums
Viewing all articles
Browse latest Browse all 204402

ListView binding to ObservableCollection - crashes when calling Clear() on iOS only

$
0
0

I am seriously stuck on a weird binding problem that causes an exception on iOS upon calling ObservableCollection.Clear(). I have created a small repro, here are the highlights.

Xaml:

<StackLayout Padding="0,20">
        <Button Text="Explode" Command="{Binding TestCommand}"/>
        <Label Text="{Binding TestMessage}" />

        <ListView Grid.Column="0" Grid.Row="1" 
                      ItemsSource="{Binding TestList}" HasUnevenRows="True">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <Grid Margin="5,0,5,0">

                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto" />
                            </Grid.ColumnDefinitions>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto" />
                            </Grid.RowDefinitions>

                            <Label Text="{Binding Title}">
                                <Label.GestureRecognizers>
                                    <TapGestureRecognizer Command="{Binding Path=BindingContext.TestCommand2, Source={x:Reference TestItemList}}" CommandParameter="{Binding .}" />
                                </Label.GestureRecognizers>
                            </Label>
                        </Grid>
                    </ViewCell>

                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>

    </StackLayout>

ViewModel:

public class MainPageViewModel : INotifyPropertyChanged
{
    public ObservableCollection<TestModel> TestList { get; set; } = new ObservableCollection<TestModel>();
    public ICommand TestCommand { get; private set; }
    public ICommand TestCommand2 { get; private set; }

    public string TestMessage { get; set; }

    public MainPageViewModel()
    {
        TestCommand = new Command(async () => { await OnTest(); });
        TestCommand2 = new Command<TestModel>(async (item) => { await OnTest2(item); });

        //initial population
        var items = GetMockItems();
        foreach (var item in items)
        {
            TestList.Add(item);
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    private async Task OnTest2(TestModel item)
    {
        if (item != null) TestMessage = item.Title;
        OnPropertyChanged("TestMessage");
    }

    private async Task OnTest()
    {
        await ProvokeError();
    }

    private async Task ProvokeError()
    {
        var items = GetMockItems();

        TestList.Clear();

        foreach (var item in items)
        {
            TestList.Add(item); //crashes here
        }
    }

    private List<TestModel> GetMockItems()
    {
        List<TestModel> items = new List<TestModel>();

        var item = new TestModel() { Title = "Item1" };
        items.Add(item);
        item = new TestModel() { Title = "Item2" };
        items.Add(item);
        item = new TestModel() { Title = "Item3" };
        items.Add(item);

        return items;
    }
}

To explain, the tap gesture is added to the label, because in my original project I also have an EventToCommand implementation that reacts to item being selected, but in addition to that I also need a command for the label specifically because I want one thing to happen when the user selects the general row, and another when he selects the label (it's a delete label). In the repro I have omitted the EventToCommand implementation, since it doesn't seem to cause the error.

Also, if I remove the tap gesture, it doesn't crash. And it works fine on Android, only crashes on iOS!

As mentioned, it crashes on TestList.Add(item), but only when TestList.Clear() has been run first. So in the sample project, everything runs fine, the listview is populated and I can tap the labels to display the corresponding item title. But when I try to repopulate the list, it crashes.

I hope some of you guys with more than a month of experience can help me, I'm completely stuck!


Viewing all articles
Browse latest Browse all 204402

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>