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

.NET MAUI中FlyoutItem内ShellContent的点击禁用问题

.NET MAUI中FlyoutItem内ShellContent的点击禁用问题

我完全懂你这个烦恼——当把多个ShellContent塞进设置了FlyoutDisplayOptions="AsMultipleItems"的FlyoutItem里时,直接给ShellContent加IsEnabled="False"根本拦不住点击跳转,而用单独FlyoutItem或者套Tab的方式虽然能禁用,但那个多余的动画实在让人头疼。

这里有两个实用的解决办法,都能避开动画问题,完美实现禁用特定ShellContent的点击:

方法一:拦截Shell的导航事件(最简单直接)

这个思路是在Shell准备导航前,检查目标页面对应的ShellContent是否处于禁用状态,如果是就取消导航。

  1. 先给每个ShellContent加上Route属性(方便后续匹配目标页面):
<FlyoutItem Title="Title" FlyoutDisplayOptions="AsMultipleItems">
    <ShellContent Route="MainPage" Title="      Сontinuous" ContentTemplate="{DataTemplate views:MainPage}" IsEnabled="True"/>
    <ShellContent Route="JingleBellsPage" Title="      Jingle Bells" ContentTemplate="{DataTemplate views:JingleBellsPage}" />
    <ShellContent Route="HeartbeatPage" Title="      Heartbeat " ContentTemplate="{DataTemplate views:heartbeatPage}" />
    <ShellContent Route="LovePage" Title="❤️      Love" ContentTemplate="{DataTemplate views:LovePage}" IsEnabled="False"/>
</FlyoutItem>
  1. 在AppShell的后台代码里,监听Navigating事件并添加拦截逻辑:
public partial class AppShell : Shell
{
    public AppShell()
    {
        InitializeComponent();
        // 注册导航事件
        Navigating += AppShell_Navigating;
    }

    private void AppShell_Navigating(object sender, ShellNavigatingEventArgs e)
    {
        // 获取当前要跳转的路由
        var targetRoute = e.Target.Location.OriginalString;
        
        // 找到对应路由的ShellContent
        var targetShellContent = Shell.Current.Items
            .OfType<FlyoutItem>()
            .SelectMany(flyout => flyout.Items.OfType<ShellContent>())
            .FirstOrDefault(sc => sc.Route == targetRoute);

        // 如果找到的ShellContent是禁用状态,就取消导航
        if (targetShellContent != null && !targetShellContent.IsEnabled)
        {
            e.Cancel();
        }
    }
}

这个方法不需要修改Flyout的UI模板,代码量少,而且不管是从Flyout点击还是其他方式触发导航,都能拦截禁用的页面,非常稳妥。

方法二:自定义Flyout项模板(更灵活控制UI)

如果还想给禁用的ShellContent做一些UI上的区分(比如变灰),可以自定义FlyoutItem的ItemTemplate,自己控制点击逻辑:

  1. 在AppShell的资源里定义自定义模板(可选添加布尔转颜色的转换器,让禁用项变灰):
<Shell.Resources>
    <DataTemplate x:Key="CustomFlyoutItemTemplate">
        <Label Text="{Binding Title}"
               IsEnabled="{Binding IsEnabled}"
               Padding="12,8"
               TextColor="{Binding IsEnabled, Converter={StaticResource BoolToColorConverter}}">
            <Label.GestureRecognizers>
                <TapGestureRecognizer Command="{Binding BindingContext.FlyoutTapCommand, Source={x:Reference Name=appShell}}"
                                      CommandParameter="{Binding}" />
            </Label.GestureRecognizers>
        </Label>
    </DataTemplate>
    <converters:BoolToColorConverter x:Key="BoolToColorConverter" TrueColor="Black" FalseColor="Gray"/>
</Shell.Resources>
  1. 给FlyoutItem指定这个模板,并确保Shell的x:Name是appShell:
<Shell x:Name="appShell" ...>
    <FlyoutItem Title="Title" FlyoutDisplayOptions="AsMultipleItems"
                ItemTemplate="{StaticResource CustomFlyoutItemTemplate}">
        <!-- 你的ShellContent列表 -->
    </FlyoutItem>
</Shell>
  1. 在AppShell后台添加点击命令:
public ICommand FlyoutTapCommand => new Command<ShellContent>(async (item) =>
{
    if (item.IsEnabled)
    {
        // 跳转到对应页面
        await Shell.Current.GoToAsync($"//{item.Route}");
    }
});

这个方法不仅能禁用点击,还能自由修改禁用项的样式,比如文字变灰、去掉高亮等,适合对UI有定制需求的场景。

两种方法都不会出现你说的烦人的动画,选哪个就看你有没有UI定制的需求啦~

备注:内容来源于stack exchange,提问作者Guf

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.22 09:29:35