Search code examples
c#androidxamarin.formsmvvmobservablecollection

Xamarin Android MVVM - Grouped CollectionView does not update UI after list changes


I have a grouped CollectionView with an ObservableCollection as ItemSource andthe list shows just fine,  with the itens grouped. The problem is that the UI does not get updated when i add or remove something from the collection. I need to pop and call the ProductsPage again to see the changes.

I even tried to refresh the entire list by calling the CreateGroups method after a change, it didn't work either.

Here´s parte of the code (i removed some unrelated code so there may be some inconsistencies)

ProdutosGroup

public class ProdutosGroup : ObservableCollection<Produto>
{
   public string Titulo { get; set; }

   public ProdutosGroup(string titulo, ObservableCollection<Produto> produtos) : base(produtos)
   {
       Titulo = titulo;
   }
}

ProductsViewModel

public ObservableCollection<Produto> Produtos { get; set; } //the actual list of products
public ObservableCollection<ProdutosGroup> ProdutosAgrupadosList { get; set; }//the grouped list

public ListaDeProdutosViewModel(int idListaDeProdutos)
{
   PopulateList();
   CreateGroups();
}

public void CarregarProdutos()
{
    this.Produtos = new ObservableCollection<Produto(App._produtoRepo.GetProdutos);
}

public void CreateGroups()
{
     var idsCat = Produtos.Select(x => x.IdCategoria).Distinct();

     var cats = new ObservableCollection<ProdutoCategoria>();
     foreach (var idCat in idsCat)
     {
         cats.Add(App._categoriaRepo.GetProdutoCategoriaById(idCat));
     }

     foreach (var item in cats)
     {
         ObservableCollection<Produto> produtosDaCategoria = new ObservableCollection<Produto>();

         foreach (var prod in Produtos)
         {
             if (prod.IdCategoria == item.Id)
                 produtosDaCategoria.Add(prod);
         }
         ProdutosAgrupadosList.Add(new ProdutosGroup(item.Descricao, new ObservableCollection<Produto>(produtosDaCategoria)));
     }
}

ProductsPage

<ContentPage.Content>
        <Grid>
            <ScrollView >
                <CollectionView ItemsSource="{Binding ProdutosAgrupadosList}" x:Name="Listas" IsGrouped="true">
                    <CollectionView.GroupHeaderTemplate>
                        <DataTemplate x:DataType="models:ProdutosGroup">
                            <Label Text="{Binding Titulo}" FontSize="28"/>
                        </DataTemplate>
                    </CollectionView.GroupHeaderTemplate>
                    <CollectionView.ItemTemplate>
                        <DataTemplate x:DataType="models:Produto">
                            <Label VerticalTextAlignment="Center" Text="{Binding Nome}" FontSize="28"/>
                        </DataTemplate>
                    </CollectionView.ItemTemplate>
                </CollectionView>
            </ScrollView>
            <ImageButton Padding="12" Source="BasketPlus" Grid.Row="1" Command="{Binding AddForm}" HorizontalOptions="End" WidthRequest="68" HeightRequest="68" VerticalOptions="End" CornerRadius="100"  Margin="0,0,16,22" BackgroundColor="{StaticResource Verde}"/>
        </Grid>
    </ContentPage.Content>

Solution

  • If you want to add an item in a group, you could simply use the following code:

    ProdutosAgrupadosList[0].Add(
        new Produto
        {
            Nome = "and"
        });     // this will add the item at the end
    

    or

    ProdutosAgrupadosList[0].Insert(1,
    new Produto
    {
        Nome = "and"
    });    // add the item after the index1 item
    

    To remove, you could either use ProdutosAgrupadosList[0].RemoveAt(index) or use a SwipeView which you could refer to CollectionView Context menus for more info. A simple demo using SwipeView like the following

    <CollectionView.ItemTemplate>
        <DataTemplate >
            <SwipeView>
                <SwipeView.LeftItems>
                    <SwipeItems>
                        <SwipeItem Text="Delete"
                                   BackgroundColor="LightPink"
                                   Command="{Binding Source={x:Reference Listas}, Path=BindingContext.DeleteCommand}"
                                   CommandParameter="{Binding}" />
                    </SwipeItems>
                </SwipeView.LeftItems>
                <StackLayout>
                    <Label VerticalTextAlignment="Center" Text="{Binding Nome}" FontSize="28"/>
                </StackLayout>
           </SwipeView>
        </DataTemplate>
    </CollectionView.ItemTemplate>
    

    That works for me based on the code in your question. For more info, you could refer to Xamarin.Forms CollectionView

    Hope it works for you.