ALI
ALI

Reputation: 5

Check a checkBox in a listView .net maui

In my project maui i want a helper to check checkBox when I select an item from the listView with multiple selection. My listView in xaml:

<ListView x:Name="listViewComande"                  
           ItemSelected="listViewArticle_ItemSelected">
     <ListView.Header >        
     </ListView.Header>
     <ListView.ItemTemplate  >
         <DataTemplate >
             <ViewCell   >
                 <Grid RowDefinitions="Auto" 
                       ColumnDefinitions="5*,20*,45*,10*,10*,10*" 
                       Padding="3,10,3,10"  ColumnSpacing="8">
                       <CheckBox Grid.Row="1" Grid.Column="0" 
                       Color="LightGray"                     
                       x:Name="chekBoxListView" />                  
                     <Label Grid.Row="1" Grid.Column="2"  Text="{Binding DesignationComande}"      FontSize="13" VerticalTextAlignment="Center"
                          HorizontalTextAlignment="Start" MaxLines="1"  FontAttributes="None"/>                  
                 </Grid>
             </ViewCell>
         </DataTemplate>
     </ListView.ItemTemplate>
 </ListView>

public class ComandeTable
 {
    [PrimaryKey, AutoIncrement]
     public int ID { get; set; }
     public string ReferenceComande { get; set; }   
     public string DesignationComande { get; set; } 
 }

private void listViewArticle_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{   
    if (e.SelectedItem != null)
    {       
    }
}

I used a bool variable but it doesn't work

Upvotes: 0

Views: 1244

Answers (3)

Stephen Quan
Stephen Quan

Reputation: 26159

I recommend creating two view models:

  • CheckedViewModel - for each item in the collection
  • MainViewModel - a parent view model that holds the ObservableCollection and the dynamic list of the selected items

We can subscribe to the CheckedViewModel.OnPropertyChanged for each item to the parent MainViewModel so that the parent view model gets notified whenever the IsChecked changes and it will recompute the SelectedItems on demand.

In MainPage.xaml.cs we implement ListView_ItemTapped to manipulate the collection view model.

// MauiProgram.cs
builder.Services.AddTransient<MainViewModel>();
builder.Services.AddTransient<MainPage>();
// CheckedViewModel.cs
public partial class CheckedViewModel : ObservableObject
{
    [ObservableProperty]
    private bool _isChecked = false;

    [ObservableProperty]
    private string _commandText = string.Empty;
}
// MainViewModel.cs
public partial class MainViewModel : ObservableObject
{
    [ObservableProperty]
    private ObservableCollection<CheckedViewModel> _checkedItems = new()
    {
        new CheckedViewModel { CommandText = "Command 1" },
        new CheckedViewModel { CommandText = "Command 2" },
        new CheckedViewModel { CommandText = "Command 3" },
    };

    public List<CheckedViewModel> SelectedItems => CheckedItems.Where(x => x.IsChecked).ToList();

    public MainViewModel()
    {
        foreach (var item in CheckedItems)
        {
            item.PropertyChanged += (s, e) =>
            {
                if (e.PropertyName == nameof(CheckedViewModel.IsChecked))
                {
                    OnPropertyChanged(nameof(SelectedItems));
                }
            };
        }
    }
}
<!-- MainPage.xaml -->
<VerticalStackLayout x:DataType="{x:Type local:MainViewModel}">
    <ListView x:Name="myView"
              ItemsSource="{Binding CheckedItems}"
              ItemTapped="myView_ItemTapped">
        <ListView.ItemTemplate>
            <DataTemplate x:DataType="{x:Type local:CheckedViewModel}">
                <ViewCell>
                    <HorizontalStackLayout>
                        <CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay}" />
                        <Label Text="{Binding CommandText}" />
                    </HorizontalStackLayout>
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
    <Label Text="{Binding SelectedItems.Count, StringFormat='{0} commands checked'}" />
    <ListView ItemsSource="{Binding SelectedItems}">
        <ListView.ItemTemplate>
            <DataTemplate x:DataType="{x:Type local:CheckedViewModel}">
                <ViewCell>
                    <Label Text="{Binding CommandText}" />
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</VerticalStackLayout>
// MainPage.xaml.cs
public partial class MainPage : ContentPage
{
    MainViewModel VM;

    public MainPage(MainViewModel VM)
    {
        InitializeComponent();
        this.VM = VM;
        BindingContext = VM;
    }

    private void myView_ItemTapped(object sender, ItemTappedEventArgs e)
    {
        VM.CheckedItems[e.ItemIndex].IsChecked = !VM.CheckedItems[e.ItemIndex].IsChecked;
    }
}

Upvotes: 0

IV.
IV.

Reputation: 9438

Your xaml demonstrates an intent to display the DesignationComande property and respond when the check box changes (either programmatically or though user interaction). This will require a model for the items in your ListView bound to those properties.

For example:

responding to checks


Finish the bindings in xaml

Bind the IsChecked property in your DataTemplate

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="checked_list_view.MainPage">
    <Grid
        RowDefinitions="*,*" >
        <ListView
            Grid.Row="0"
            x:Name="listViewComande"                  
            BackgroundColor="Azure">
            <ListView.ItemTemplate >
                <DataTemplate>
                    <ViewCell>
                        <Grid 
                            RowDefinitions="Auto" 
                            ColumnDefinitions="Auto,20*,45*,10*,10*,10*" 
                            Padding="3,10,3,10" 
                            ColumnSpacing="8">
                            <CheckBox 
                                IsChecked="{Binding IsChecked}"
                                Grid.Row="1" 
                                Grid.Column="0" 
                                Color="CornflowerBlue" />
                            <Label 
                                Grid.Row="1" 
                                Grid.Column="2"  
                                BackgroundColor="LightGreen"
                                Text="{Binding DesignationComande}"      
                                FontSize="13" VerticalTextAlignment="Center"                            
                                HorizontalTextAlignment="Start" MaxLines="1"  
                                HorizontalOptions="Fill"
                                FontAttributes="None"
                                Padding="10,0"/>
                        </Grid>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
        <Editor 
            Grid.Row="1"
            Text="{Binding EditorText}"/>
    </Grid>
</ContentPage>

Make a Model for items in the ListView

This functionality requires a bindable property for IsChecked that fires a PropertyChanged event for the check boxes.

class CheckableCommand : INotifyPropertyChanged
{
    public string DesignationComande { get; set; }
    public override string ToString() => DesignationComande;

    public bool IsChecked
    {
        get => _isChecked;
        set
        {
            if (!Equals(_isChecked, value))
            {
                _isChecked = value;
                OnPropertyChanged();
            }
        }
    }
    bool _isChecked = false;
    private void OnPropertyChanged([CallerMemberName]string caller = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(caller));
    }
    public event PropertyChangedEventHandler PropertyChanged;
}

Glue it all together

In this sample, the code-behind for the MainPage sets the ItemsSource of the ListView (you could also do this in xaml) to an observable collection of CheckableCommand and subscribes to the PropertyChanged notification of the items.

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        BindingContext = this;
        InitializeComponent();
        listViewComande.ItemsSource = new ObservableCollection<CheckableCommand>
        {
            new CheckableCommand{ DesignationComande = "Command 1" },
            new CheckableCommand{ DesignationComande = "Command 2" },
            new CheckableCommand{ DesignationComande = "Command 3" },
        };
        foreach (CheckableCommand command in listViewComande.ItemsSource)
        {
            command.PropertyChanged += (sender, e) =>
            {
                switch (e.PropertyName) 
                {
                    case nameof(CheckableCommand.IsChecked):
                        var checkedCommands = 
                            listViewComande
                            .ItemsSource
                            .OfType<CheckableCommand>()
                            .Where (_ => _.IsChecked)
                            .ToList();
                        if(checkedCommands.Any())
                        {
                            EditorText = string.Join(Environment.NewLine, checkedCommands);
                        }
                        else
                        {
                            EditorText = "No checked commands at this time.";
                        }
                        break;
                }
            };            
            listViewComande.ItemSelected += (sender, e) =>
            {
                // Option to check the checkbox when item is selected.
                if (e.SelectedItem is CheckableCommand cmd) cmd.IsChecked = true;
            };
        }
        EditorText = "Hello, I'll be keeping track of your checked commands.";
    }
    public string EditorText
    {
        get => _editorText;
        set
        {
            if (!Equals(_editorText, value))
            {
                _editorText = value;
                OnPropertyChanged();
            }
        }
    }
    string _editorText = string.Empty;
}

Upvotes: 0

Arvind Chourasiya
Arvind Chourasiya

Reputation: 17432

What I understood, you want to check a Checkbox when you select an item in the listView. This is how you can do it

private void ListView_ItemTapped(object sender, ItemTappedEventArgs e)
{
    var viewCell = ((ListView)sender);
    var checkbox = viewCell.GetVisualTreeDescendants().Where(x => x.GetType() == typeof(CheckBox));
    var currentCheckbox = (CheckBox)checkbox.ElementAt(e.ItemIndex);
    //var currentCheckbox = (CheckBox)checkbox.ToList()[e.ItemIndex];
    if (!currentCheckbox.IsChecked)
        currentCheckbox.IsChecked = true;
    else
        currentCheckbox.IsChecked = false;
}

Note one thing, here ListView_ItemTapped is ItemTapped not ItemSelected.

Upvotes: 0

Related Questions