SwipeView only responsive on some rows after executing a swipe! (until page manullay navigated)

269 Views Asked by At

I have a complex listview comprised of a header template to group collections within a collection, I used the tutorial below which uses the example of grouping rooms by hotels within a listview:

https://www.c-sharpcorner.com/article/xamarin-forms-expandable-listview-with-a-sub-listview-mvvm-pattern/

I've added SwipeView to the items, but after one swipe to delete an item from a sub collection, the swipe gestures only respond on random rows.

This seems like a bug, possibly due to my use of my layered model/view model structure?

Any advice or tips on this? I've used both SwipeItems and SwipeItemView but neither made a difference. Also, it's sometimes the first items in the grid that don't swipe but the last items do...

I've also used InitialiseComponent after an item is removed from the collection but I don't like how the page scrolls to the top, and scrolltoasync does look great either.

My ListView's ItemSource is an ObservableCollection that contains sub Observable collections in it - LogItems, with FictionList, HistoryList, etc. When I get the retrieved item swipes, carrry out a foreach on the subcollections to remove it from the collection and the UI updates accordingly. However, then not all items are swipable....

I've been struggling with this bug so any help would be appreciated.

    <Grid x:Name="Grid2" Margin="0,-23,0,0" 
             MinimumHeightRequest="500" 
              BackgroundColor="Transparent"
              VerticalOptions="Fill" >
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
                <RowDefinition Height="30"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>

            <StackLayout x:Name="Stack" Padding="0,15,1,20" 
             BackgroundColor="Transparent"
                         VerticalOptions="Start" HeightRequest="1200" 
                         >
                    <ListView
                        x:Name="categoriesList"
                        Grid.Row="1"
                        HasUnevenRows="True"
                        HeightRequest="10"
                        BackgroundColor="White"
                        IsGroupingEnabled="True"
                        IsPullToRefreshEnabled="false"
                        ItemsSource="{Binding LogItems}"
                        IsRefreshing="{Binding IsBusy, Mode=OneWay}"
                        RefreshCommand="{Binding ExecuteRefreshItemsCommand}"
                            SeparatorVisibility="None"                      
                            >
    <ListView.ItemTemplate>
              <DataTemplate >
           

        <ViewCell Height="70" >
                    <StackLayout Orientation="Vertical" 

    VerticalOptions="Start" BackgroundColor="White">                                        
                             <SwipeView>
                                  <SwipeView.RightItems>
                                       <SwipeItems Mode="Reveal" SwipeBehaviorOnInvoked="Close">
                                            <SwipeItem
                                                 Text = "Delete" IconImageSource="deleteIcon3.png" BackgroundColor="Red" Invoked="SwipeView_SwipeInitiated"/>                      
                                       </SwipeItems>
       

                            </SwipeView.RightItems>
                               <SwipeView.Content>  
                                    <Grid> 

        <Label
        Grid.Row="1"                                                          
        Grid.Column="0"
        VerticalOptions="Center"
        FontAttributes="None"                                       
        Text="{Binding .Log.Name }"
        TextColor="Black"
        Margin="0, 0,0, 0"
        Padding="10,10,0,0"
        FontFamily="Hiragino Sans"
        FontSize="14"
        HeightRequest="53"
        BackgroundColor="White"
        />

...

</Grid>


Code behind

        public void SwipeView_SwipeInitiated(object sender, 
        EventArgs e)
        {
            var item = sender as SwipeItemView;
            myLogsModel model = item.BindingContext as myLogsModel;

                if (model.BookCategory == "Fiction")
                {
                    foreach (var q in ViewModel.FictionList)
                    {
                        if (q.Name == model.Name)
                        {
                            ViewModel.BookList.Remove(q);                                                                                                                                                                                                              
                            break;
                        }
                    }
                }

 //model - myLogsModel
        if (model.Log.LogCategory == "Fiction")
        {
            foreach (var q in ViewModel.FictionList)
            {
                if (q.MealName == model.Log.Name)
                {
                    ViewModel.FictionList.Remove(q);
                    NotifyPropertyChanged();
                    ViewModel.DeleteLog(q);   
                    break;
                }
            }
        }

I then, use a try-catch to clear the list and re-add with new sub collection data which works:

 try
        {
            if (ViewModel.IsBusy)
                return;
            ViewModel.IsBusy = true;
            ViewModel.LogItems.Clear();

            ObservableCollection<BookTypes> categoryitems = new ObservableCollection<BookTypes>() {
             new BookTypes("Fiction", ViewModel.FictionList),
             new BookTypes("History", ViewModel.HistoryList),
             new BookTypes("Politics", ViewModel.PoliticsList),
            };

            if (categoryitems != null && categoryitems.Count > 0)
            {   
                ViewModel.LogItems.Add(new LogTypesModel(types));
                ViewModel.OnPropertyChanged("LogItems");
            }
            else { ViewModel.IsEmpty = true; }
        }
        catch (Exception ex)
        {
            IsBusy = false;
            Debug.WriteLine(ex);
        }
        finally
        {
            ViewModel.IsBusy = false;
            OnPropertyChanged();
        }
1

There are 1 best solutions below

4
Lucas Zhang On

You need to use ObservableCollection instead of IList .ObservableCollection also implements INotifyCollectionChanged interface while List doesn't. It will update UI when we add or remove items .

In your case , when you remove an item from categoryitems . The listview will not refresh . So the swipe event will never been invoked any more .

For more details you could check this thread ,