Search code examples
c#mvvmmauimaui-community-toolkitcommunity-toolkit-mvvm

C# Maui - Implement Commands on list of check boxes


I have a simple application with a button that adds entries to a CollectionView, each entry of data type "Person" has a CheckBox and a label.

The problem (i think) is that i'm trying to implement the command behaviour on the checkboxes. This command is implemented in the ViewModel.

Whenever i add a new Person, the debugger always breaks here:

enter image description here

Here is my View:

<?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"
             x:Class="MauiAppCheckBoxExample.MainPage"
             xmlns:model="clr-namespace:MauiAppCheckBoxExample.Model"
             xmlns:viewmodel="clr-namespace:MauiAppCheckBoxExample.ViewModel"
             xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
             x:DataType="viewmodel:MainPageViewModel">

    <Grid
        RowDefinitions="*,50">
    <CollectionView
            x:Name ="myCollectionView"
            ItemsSource="{Binding People}"
            SelectionMode="Single"
        Grid.Row="0">


        <CollectionView.ItemTemplate EnableViewState ="false">
            <DataTemplate x:DataType="model:Person">
                <Grid
                        ColumnDefinitions="50,*">

                        <CheckBox
                            x:Name="WholeNameCheckbox"
                              IsChecked="{Binding SportingFan, Mode =TwoWay}"
                              HorizontalOptions="Center">
                            <CheckBox.Behaviors>
                                <toolkit:EventToCommandBehavior
                                EventName="CheckedChanged"
                                Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodel:MainPageViewModel}}, Path = CheckBoxCheckedCommand}"
                                CommandParameter="{Binding IsChecked, Source={x:Reference WholeNameCheckbox}}"/>

                            </CheckBox.Behaviors>
                        </CheckBox>

                        <Label Text="{Binding Name}"
                               Padding="10"
                               Grid.Column="1"/>
                </Grid>
            </DataTemplate>
        </CollectionView.ItemTemplate>
    </CollectionView>

        <Button Grid.Row="1"
                Text="Click Me"
                Command="{Binding AddPeopleCommand}"/>

    </Grid>
</ContentPage>

The ViewModel:

using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using MauiAppCheckBoxExample.Model;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MauiAppCheckBoxExample.ViewModel
{
    public partial class MainPageViewModel : ObservableObject
    {
        public ObservableCollection<Person> People { get; }
        public MainPageViewModel()
        { 

            People = new();

        }

        [RelayCommand]
        public async Task OnCheckBoxCheckedAsync(bool value)
        {
            await Task.Delay(1000);
        }

        [RelayCommand]
        public void AddPeople()
        {
            Person p = new Person();
            p.Name = "Valentyna";
            p.SportingFan = false;
            People.Add(p);

            p = new Person();
            p.Name = "Gil";
            p.SportingFan = false;
            People.Add(p);
        }
    }
}

And the model:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MauiAppCheckBoxExample.Model
{
    public class Person
    {
        public string? Name { get; set; }
        public bool SportingFan { get; set; }


    }
}

Can you guys pls help a new guy coding with maui? >.<


Solution

  • Yes, the usage of Relative bindings for the toolkit:EventToCommandBehavior of CheckBox is not right.

    We could just replace the following code:

     Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodel:MainPageViewModel}}, Path = CheckBoxCheckedCommand}"
    

    with:

    Command="{Binding Source={x:Reference page}, Path=BindingContext.CheckBoxCheckedCommand}"
    

    Note: The page is the property of current page:

     x:Name="page"
    

    For more information about Relative bindings, you can check document: Relative bindings.