.netobservablecollectionmaui

.net maui Cannot get updated fields in an Observable collection to update in bound collection view


I'm trying to update actual fields in an ObservableCollection that is bound to a CollectionView.

The CollectionView updates fine on adding, removing items, but not if I programmatically change an item in the list.

I understand from this post Observable collection not updated that I need to implement INotifyPropertyChanged.

I am using the CommunityToolkit.Mvvm and had hoped that this kind of magic would be automatically done, but it appears not. I don't have the C# knowledge to know how to do what I want. Could someone help me please :)

There is a repo at https://github.com/gfmoore/TestCollectionBinding

and here is my current code:

Views.MyItem.cs


namespace TestCollectionBinding.Views;

public class MyItem
{
  public string Name { get; set; }
  public string Device { get; set; }
}

ViewModels.MainPageViewModel.cs

using CommunityToolkit.Mvvm.ComponentModel;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using TestCollectionBinding.Views;

namespace TestCollectionBinding.ViewModels;

public partial class MainPageViewModel : ObservableObject
{
  [ObservableProperty]
  public ObservableCollection<MyItem> myItems = new()
  {
    new MyItem
    {
      Name = "Heart Rate Monitor",
      Device = "12:12:12:12:AB"
    },

    new MyItem
    {
      Name = "Cadence",
      Device = "34:34:34:34:CD"
    }
  };

  //show details
  public ICommand ChangeCommand => new Command(ChangeControl);
  public void ChangeControl()
  {
    //change device
    foreach (MyItem q in MyItems)
    {
      q.Device = "***********";
    }
    Console.WriteLine($"Change device");
  }
}

and the MainPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:TestCollectionBinding.ViewModels"
             x:Class="TestCollectionBinding.MainPage">

  <ContentPage.BindingContext>
    <local:MainPageViewModel />
  </ContentPage.BindingContext>

  <StackLayout>
    <Label Text="Items" 
           FontSize="20"
           TextColor="Blue"/>

    <CollectionView x:Name="MyItemsList"
                    ItemsSource="{Binding MyItems}">
      <CollectionView.ItemTemplate>
        <DataTemplate>
          <Grid
            Margin="10, 0, 10, 10"
            ColumnDefinitions="200, 200">
            <Label Grid.Column="0" 
                   Text="{Binding Name}" 
                   FontSize="20"/>

            <Label Grid.Column="1" 
                   Text="{Binding Device}" 
                   FontSize="20"/>            
          </Grid>
   
        </DataTemplate>
      </CollectionView.ItemTemplate>
    </CollectionView>

    <Button
      Text="Change device names"
      FontFamily="20"
      WidthRequest="150"
      Command="{Binding ChangeCommand}" />
    
  </StackLayout>

</ContentPage>

So the MainPage displays two items in the list and when I hit the button the command cycles through the list and just replaces the Device property with "*********".

I expect to see these changes in the displayed list.

Oh for the days of ... dBase II lol

G


Solution

  • from the docs

    public class MyItem : ObservableObject
    {
        private string name;
    
        public string Name
        {
            get => name;
            set => SetProperty(ref name, value);
        }
    }