I have a custom control, that represent the stucture of a meeting room
Meeting room name, Users, and a checkbox to invite users.
The code looks like
<StackLayout>
<inputLayout:SfTextInputLayout
Hint="{Binding Hint, Source={x:Reference UserExpander}}"
HorizontalOptions="StartAndExpand"
OutlineCornerRadius="8">
<Entry Text="{Binding RoomName, Source={x:Reference UserExpander}}" />
</inputLayout:SfTextInputLayout>
<expander:SfExpander>
<expander:SfExpander.Header>
<Grid
ColumnDefinitions="50,60"
ColumnSpacing="10">
<Label
FontFamily="Mat"
FontSize="Header"
HorizontalTextAlignment="Center"
Text="{Static helpers:IconFont.Group}"
VerticalTextAlignment="Center" />
<Label
Grid.Column="1"
Text="Students" />
</Grid>
</expander:SfExpander.Header>
<expander:SfExpander.Content>
<CollectionView
ItemsSource="{Binding Users, Source={x:Reference UserExpander}}"
SelectionMode="None">
<CollectionView.ItemTemplate>
<DataTemplate>
<Border Margin="2">
<Border.StrokeShape>
<RoundRectangle CornerRadius="8" />
</Border.StrokeShape>
<Grid
Margin="5,5,5,0"
ColumnDefinitions="40,*"
RowDefinitions="*,*">
<Label
Grid.Column="1"
Text="{Binding Name}" />
<Label
Grid.Row="3"
Grid.Column="1"
Text="{Binding Email}" />
<chechbox:SfCheckBox
Grid.RowSpan="3"
HorizontalOptions="End"
IsChecked="{Binding IsParticipant}"
VerticalOptions="End">
<chechbox:SfCheckBox.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding HandleCheckBoxCommand, Source={RelativeSource AncestorType={x:Type ContentView}}}"
CommandParameter="{Binding .}" />
</chechbox:SfCheckBox.GestureRecognizers>
</chechbox:SfCheckBox>
</Grid>
</Border>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</expander:SfExpander.Content>
</expander:SfExpander>
</StackLayout>
</ContentView>`
public partial class UserDetailsExpander : ContentView {
public UserDetailsExpander() {
InitializeComponent();
}
public static readonly BindableProperty HintProperty = BindableProperty.Create(
nameof(Hint), typeof(string), typeof(UserDetailsExpander));
public string Hint {
get => (string)GetValue(HintProperty);
set => SetValue(HintProperty, value);
}
public static readonly BindableProperty RoomNameProperty = BindableProperty.Create(
nameof(RoomName), typeof(string), typeof(UserDetailsExpander), string.Empty,
BindingMode.TwoWay);
public string RoomName {
get => (string)GetValue(RoomNameProperty);
set => SetValue(RoomNameProperty, value);
}
public static readonly BindableProperty UsersProperty = BindableProperty.Create(
nameof(Users), typeof(IEnumerable), typeof(UserDetailsExpander));
public IEnumerable Users {
get => (IEnumerable)GetValue(UsersProperty);
set => SetValue(UsersProperty, value);
}
public static readonly BindableProperty HandleCheckBoxCommandProperty = BindableProperty.Create(
nameof(HandleCheckBoxCommand), typeof(RelayCommand), typeof(UserDetailsExpander));
public RelayCommand HandleCheckBoxCommand {
get => (RelayCommand)GetValue(HandleCheckBoxCommandProperty);
set => SetValue(HandleCheckBoxCommandProperty, value);
}
for the most part, this is working. I display my list of users, I can put a meeting name, but the HandleCheckBoxCommand is not working.
I am using this control here
<ContentPage
x:Class="DemyAI.Views.NewTestPage"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:DemyAI.Controls"
xmlns:mct="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
xmlns:vm="clr-namespace:DemyAI.ViewModels"
x:DataType="vm:NewTestPageViewMode">
<ContentPage.Behaviors>
<mct:EventToCommandBehavior
Command="{Binding AppearingCommand}"
EventName="Appearing" />
</ContentPage.Behaviors>
<VerticalStackLayout Margin="10">
<controls:UserDetailsExpander
HandleCheckBoxCommand="{Binding HandleCheckBoxCommand}"
Hint="Name of the test"
RoomName="{Binding RoomName}"
Users="{Binding Users}" />
<Button Command="{Binding StartMeetingCommand}" />
</VerticalStackLayout>
</ContentPage>
and the command comes from this viewModel
public ObservableCollection<User> Users { get; set; } = [];
public ObservableCollection<User> Invited { get; set; } = [];
[ObservableProperty]
string? roomName;
[RelayCommand]
async Task Appearing() {
await GetStudents();
}
private async Task GetStudents() {
Users.Clear();
var data = await dataService.GetByRole<User>("Users", Roles.Student.ToString());
foreach(var filterUser in data) {
Users.Add(filterUser);
}
}
[RelayCommand]
void HandleCheckBox(User user) {
if(user.IsParticipant) {
Invited.Add(user);
} else {
Invited.Remove(user);
}
}
[RelayCommand]
async Task StartMeeting() {
if(string.IsNullOrEmpty(RoomName)) {
await appService.DisplayAlert("Error", "The room name cannot be empty", "OK");
return;
}
var loogedUser = await authenticationService.GetLoggedInUser();
var databaseUer = await dataService.GetByUidAsync<User>("Users", loogedUser!.Uid);
var meetingOptions = new MeetingOptions {
EnableAdvancedChat = true,
EnableEmojiReactions = true,
EnableNoiseCancellationUi = true,
EnableHandRaising = true,
EnablePrejoinUi = true,
EnablePipUi = true,
EnableScreenshare = true,
EnableVideoProcessingUi = true,
EnablePeopleUi = false,
EnableChat = true
// Set other meeting option properties as needed
};
try {
var roomURL = await meetingService.CreateMeetingAsync(RoomName, meetingOptions, Constants.DAILY);
foreach(var userInvited in Invited) {
string userEmail = userInvited.Email;
await EmailHelper.SendEmail(userEmail, RoomName, databaseUer, roomURL, null);
}
} catch(Exception ex) {
// Handle any exceptions that might occur during the meeting creation
await appService.DisplayAlert("Error", $"Error creating meeting: {ex.Message}", "OK");
}
}
}
I am expecting that the HandleCheckBox trigger.
I tried to use the ancestor type
I named the controller.
I put two mode
I tried BindingContext.HandleCheckBoxCommand
The reason it's probably not working is because you are trying to add a command to a TapGestureRecognizor to a Toggleable control(first responders), what you should be doing instead is using the StateChanged event and triggering the command through it.
In syncfusions docs you can see it has a StateChanged event use it like this:
<syncfusion:SfCheckBox StateChanged="CheckBox_StateChanged"/>
In your ContentViews class add the event and trigger your command
private void CheckBox_StateChanged(object sender, StateChangedEventArgs e)
{
//HandleCommand should be triggered here and you can get the relevant state from events
}