Reputation: 5
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
Reputation: 26159
I recommend creating two view models:
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
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:
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
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