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

.NET MAUI中是否存在MenuItem的IsChecked与Checkable等效实现?

实现.NET MAUI中绑定设置项的可勾选菜单项

可以实现,以下是完整的分步方案:

1. 完善Settings类的属性变更通知

首先要确保设置项的变更能通知到绑定系统,推荐使用单例类+INotifyPropertyChanged的实现方式(比静态类更适配MAUI绑定机制):

using System.ComponentModel;
using System.Runtime.CompilerServices;
using Microsoft.Maui.Storage;

namespace YourAppNamespace;

public class Settings : INotifyPropertyChanged
{
    // 单例实例
    private static readonly Settings _instance = new();
    public static Settings Instance => _instance;

    public event PropertyChangedEventHandler? PropertyChanged;

    private void OnPropertyChanged([CallerMemberName] string? propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    // 通用设置更新方法
    private void SetPreference<T>(ref T backingField, T newValue, [CallerMemberName] string? propertyName = null)
    {
        if (!EqualityComparer<T>.Default.Equals(backingField, newValue))
        {
            backingField = newValue;
            Preferences.Set(propertyName!, newValue);
            OnPropertyChanged(propertyName);
        }
    }

    // 示例设置项
    private bool _isSetting1Enabled;
    public bool IsSetting1Enabled
    {
        get => _isSetting1Enabled;
        set => SetPreference(ref _isSetting1Enabled, value);
    }

    // 构造函数:从Preferences加载初始值
    private Settings()
    {
        _isSetting1Enabled = Preferences.Get(nameof(IsSetting1Enabled), false);
    }
}

2. 自定义可勾选的MenuFlyoutItem

实现CheckableMenuFlyoutItem,处理勾选状态切换、事件触发和UI显示:

using Microsoft.Maui.Controls;

namespace YourAppNamespace;

internal class CheckableMenuFlyoutItem : MenuFlyoutItem
{
    // 注册绑定属性(必须用BindableProperty才能支持数据绑定)
    public static readonly BindableProperty IsCheckedProperty =
        BindableProperty.Create(nameof(IsChecked), typeof(bool), typeof(CheckableMenuFlyoutItem), false,
            propertyChanged: OnIsCheckedChanged);

    public static readonly BindableProperty IsCheckableProperty =
        BindableProperty.Create(nameof(IsCheckable), typeof(bool), typeof(CheckableMenuFlyoutItem), true);

    public bool IsChecked
    {
        get => (bool)GetValue(IsCheckedProperty);
        set => SetValue(IsCheckedProperty, value);
    }

    public bool IsCheckable
    {
        get => (bool)GetValue(IsCheckableProperty);
        set => SetValue(IsCheckableProperty, value);
    }

    // 勾选/取消勾选事件
    public event EventHandler? Checked;
    public event EventHandler? Unchecked;

    public CheckableMenuFlyoutItem()
    {
        // 绑定点击事件切换勾选状态
        Clicked += OnItemClicked;
    }

    private void OnItemClicked(object? sender, EventArgs e)
    {
        if (IsCheckable)
        {
            IsChecked = !IsChecked;
        }
    }

    // 勾选状态变更时的处理逻辑
    private static void OnIsCheckedChanged(BindableObject bindable, object oldValue, object newValue)
    {
        var item = (CheckableMenuFlyoutItem)bindable;
        bool isChecked = (bool)newValue;

        // 触发对应事件
        if (isChecked)
        {
            item.OnChecked(EventArgs.Empty);
        }
        else
        {
            item.OnUnchecked(EventArgs.Empty);
        }

        // 更新UI显示:在文本前添加/移除勾选标记
        item.UpdateCheckMarkDisplay();
    }

    protected virtual void OnChecked(EventArgs e)
    {
        Checked?.Invoke(this, e);
    }

    protected virtual void OnUnchecked(EventArgs e)
    {
        Unchecked?.Invoke(this, e);
    }

    private void UpdateCheckMarkDisplay()
    {
        string originalText = Text?.Replace("✓ ", "") ?? string.Empty;
        Text = IsChecked ? $"✓ {originalText}" : originalText;
    }
}

3. XAML中的绑定使用

在XAML中引用自定义控件,并绑定到Settings实例的属性:

首先添加命名空间(替换为你的项目命名空间):

xmlns:local="clr-namespace:YourAppNamespace"

然后使用自定义菜单项:

<MenuFlyoutSubItem Text="Date Display (Input)">
    <local:CheckableMenuFlyoutItem
        Name="SimpleTimeInputCheckbox"
        Text="Simple Time"
        IsCheckable="True"
        IsChecked="{Binding Source={x:Static local:Settings.Instance}, Path=IsSetting1Enabled, Mode=TwoWay}" />
</MenuFlyoutSubItem>

4. 进阶:实现类似WPF的StaysOpenOnClick效果

MAUI默认点击菜单项会关闭菜单,若需要点击勾选项时保持菜单打开,需添加平台特定处理:

Android平台(自定义渲染器)

using Android.Content;
using Microsoft.Maui.Controls.Platform.Android;
using YourAppNamespace;
using YourAppNamespace.Platforms.Android;

[assembly: ExportRenderer(typeof(CheckableMenuFlyoutItem), typeof(CheckableMenuFlyoutItemRenderer))]
namespace YourAppNamespace.Platforms.Android;

public class CheckableMenuFlyoutItemRenderer : MenuFlyoutItemRenderer
{
    public CheckableMenuFlyoutItemRenderer(Context context) : base(context)
    {
    }

    protected override void OnElementChanged(ElementChangedEventArgs<MenuFlyoutItem> e)
    {
        base.OnElementChanged(e);

        if (Control != null && e.NewElement is CheckableMenuFlyoutItem item)
        {
            // 设置原生Android菜单的勾选属性
            Control.SetCheckable(item.IsCheckable);
            Control.SetChecked(item.IsChecked);

            // 点击时阻止菜单关闭,并切换勾选状态
            Control.Click += (s, args) =>
            {
                if (item.IsCheckable)
                {
                    args.Handled = true;
                    item.IsChecked = !item.IsChecked;
                    Control.SetChecked(item.IsChecked);
                }
            };
        }
    }
}

iOS平台(自定义渲染器)

using UIKit;
using Microsoft.Maui.Controls.Platform.iOS;
using YourAppNamespace;
using YourAppNamespace.Platforms.iOS;

[assembly: ExportRenderer(typeof(CheckableMenuFlyoutItem), typeof(CheckableMenuFlyoutItemRenderer))]
namespace YourAppNamespace.Platforms.iOS;

public class CheckableMenuFlyoutItemRenderer : MenuFlyoutItemRenderer
{
    protected override void OnElementChanged(ElementChangedEventArgs<MenuFlyoutItem> e)
    {
        base.OnElementChanged(e);

        if (e.NewElement is CheckableMenuFlyoutItem item)
        {
            // 创建带状态的原生iOS菜单项
            var action = UIAction.Create(item.Text, null, (action) =>
            {
                if (item.IsCheckable)
                {
                    item.IsChecked = !item.IsChecked;
                    action.State = item.IsChecked ? UIMenuElementState.On : UIMenuElementState.Off;
                }
            });
            action.State = item.IsChecked ? UIMenuElementState.On : UIMenuElementState.Off;
            Control = action;
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 08:35:39