Search code examples
xamarinxamarin.formsbindinguicollectionviewobservablecollection

Xamarin - CollectionView bind on ObservableCollection issue


I'm experiencing a really strange issue trying to print an observableCollection of object in a CollectionView. I want to have a grid of 42 block and in each one print a number from 1 to 42. When I click on a block, I want its background to turn green.

Here is my code (pretty simple) :

Model :

public class Case
    {
        public int Id { get; set; }
        public string ColorToPrint { get; set; }

        public Case(int id, string color)
        {
            Id = id;
            ColorToPrint = color;
        }
    }

ViewModel :

public ICommand SelectionChangedCommand { get; set; }
        public GridViewModel() 
        {
            Cases = new ObservableCollection<Case>();
            for (int i=1; i<=42; i++)
            {
                Case c = new Case(i, "Grey");
                Cases.Add(c);
            }

            SelectionChangedCommand = new Command(OnSelectionChanged);

        }

        private void OnSelectionChanged()
        {
            Case c = new Case(SelectedCase.Id, "Green");
            Cases[SelectedCase.Id - 1] = c;
        }

        private ObservableCollection<Case> cases;
        public ObservableCollection<Case> Cases
        {
            get => cases;
            set
            {
                cases = value;
                OnPropertyChanged(nameof(Cases));
            }
        }

        private Case selectedCase;
        public Case SelectedCase
        {
            get => selectedCase;
            set
            {
                selectedCase = value;
                OnPropertyChanged(nameof(SelectedCase));
            }
        }
    }

And my page :

<Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <CollectionView ItemsSource="{Binding Cases}"
                            SelectionMode="Single"
                            SelectedItem="{Binding SelectedCase}"
                            SelectionChangedCommand="{Binding SelectionChangedCommand}"
                            Grid.Column="0"
                            Grid.Row="0"
                            ItemsLayout="VerticalGrid, 6"
                            Margin="20">
            <CollectionView.ItemTemplate>
                <DataTemplate>
                    
                    <Frame Padding="2"
                           BackgroundColor="Transparent">
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup Name="CommonStates">
                                <VisualState Name="Normal" />
                                <VisualState Name="Selected">
                                    <VisualState.Setters>
                                        <Setter Property="BackgroundColor" Value="Transparent"/>
                                    </VisualState.Setters>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <Frame BorderColor="Black"
                                MinimumHeightRequest="20"
                                CornerRadius="5"
                                BackgroundColor="{Binding ColorToPrint}">
                            <Label Text="{Binding Id}"
                                   TextColor="Black"
                                   FontAttributes="Bold"
                                   FontSize="15"
                                   HorizontalOptions="Center"
                                   VerticalOptions="Center"
                                   />
                        </Frame>
                        
                    </Frame>
                </DataTemplate>
                </CollectionView.ItemTemplate>
            </CollectionView>
    </Grid>

Of course, on my page.cs the viewmodel is define as the bindingContext.

So this code is working pretty well but I got a strange behaviour erasing the number in a block if I click on it (color change well) and reapearing if I click on another block. It seems also that this behaviour is happing ramdomly and not all time.

I've been lokking for a solution for my entire afternoon and I would really appreciate a bit of help on that.

Thanks everyone and excuse my pretty bad english ..

Tried different way of updating my observablecollection and also a lot of things with the propertychange event


Solution

  • This issue can be replicated on my side. To fix the issue, you can replace the outside Frame of the items in CollectionView with Grid or StackLayout like below:

    
                <CollectionView ItemsSource="{Binding Cases}" 
                                SelectionMode="Single"
                                SelectedItem="{Binding SelectedCase}"
                                SelectionChangedCommand="{Binding SelectionChangedCommand}"
                                Grid.Column="0"
                                Grid.Row="0"
                                                           
                                ItemsLayout="VerticalGrid, 6"
                                Margin="20">
                    <CollectionView.ItemTemplate>
                        <DataTemplate>
    
                            <Grid Padding="2"
                               >
                                <VisualStateManager.VisualStateGroups>
                                    <VisualStateGroup Name="CommonStates">
                                        <VisualState Name="Normal" />
                                        <VisualState Name="Selected">
                                            <VisualState.Setters>
                                                <Setter Property="BackgroundColor" Value="Transparent"/>
                                            </VisualState.Setters>
                                        </VisualState>
                                    </VisualStateGroup>
                                </VisualStateManager.VisualStateGroups>
                                
                                <Frame BorderColor="Black"
                                    MinimumHeightRequest="40"
                                    CornerRadius="5"
                                    BackgroundColor="{Binding ColorToPrint}">
                                    <Label Text="{Binding Id}"
                                       TextColor="Black"
                                       FontAttributes="Bold"
                                       FontSize="15"
                                       HorizontalOptions="Center"
                                       VerticalOptions="Center"
                                       />
                                </Frame>
                             
                            </Grid>
                        </DataTemplate>
                    </CollectionView.ItemTemplate>
                </CollectionView>