You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MAUI自定义控件HandleCheckBoxCommand绑定失效问题求助

问题:自定义控件中CheckBox的命令无法触发

我开发了一个代表会议室结构的自定义控件,包含会议室名称、用户列表以及用于邀请用户的复选框。控件能正常显示用户列表、设置会议室名称,但HandleCheckBoxCommand始终无法触发。


自定义控件XAML代码

<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);
    }
}

页面中使用自定义控件的代码

<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>

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) {
        await appService.DisplayAlert("Error", $"Error creating meeting: {ex.Message}", "OK");
    }
}

已尝试的解决方法

  • 使用祖先类型绑定
  • 命名控件绑定
  • 设置双向绑定
  • 使用BindingContext.HandleCheckBoxCommand绑定

期望点击复选框时触发HandleCheckBox命令,但所有尝试均未解决问题。

内容的提问来源于stack exchange,提问作者Natash Dimas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 01:29:56