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

.NET MAUI中能否在Shell外实现可动态更新菜单项的FlyoutWindow/汉堡菜单?

.NET MAUI中能否在Shell外实现可动态更新菜单项的FlyoutWindow/汉堡菜单?

当然可以!完全不用被Shell的限制绑住,我给你分享两种实用的实现思路,都是脱离Shell也能轻松搞定的:

一、自定义可动态绑定的侧边菜单组件

这是最灵活的方案,完全自己掌控菜单的样式和逻辑:

  1. 先定义菜单数据模型
    先写一个简单的MenuItemModel,用来存储菜单的标题、图标和点击命令:

    public class MenuItemModel : ObservableObject
    {
        private string _title;
        public string Title
        {
            get => _title;
            set => SetProperty(ref _title, value);
        }
    
        private string _icon;
        public string Icon
        {
            get => _icon;
            set => SetProperty(ref _icon, value);
        }
    
        public ICommand Command { get; set; }
    }
    
  2. 创建自定义侧边菜单控件
    做一个ContentView作为菜单容器,用CollectionView来绑定菜单项,这样数据更新时UI会自动刷新:

    <ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 x:Class="YourApp.Controls.CustomFlyoutMenu">
        <ContentView.Content>
            <Frame BackgroundColor="#f5f5f5" 
                   WidthRequest="280"
                   CornerRadius="0"
                   HorizontalOptions="Start">
                <StackLayout Margin="10">
                    <Label Text="自定义菜单" FontSize="Large" FontAttributes="Bold" Margin="0,0,0,20"/>
                    <CollectionView ItemsSource="{Binding MenuItems}"
                                    SelectionMode="None">
                        <CollectionView.ItemTemplate>
                            <DataTemplate>
                                <StackLayout Orientation="Horizontal" Padding="10" Margin="0,5">
                                    <Image Source="{Binding Icon}" WidthRequest="24" HeightRequest="24" Margin="0,0,10,0"/>
                                    <Label Text="{Binding Title}" FontSize="Medium" VerticalOptions="Center"/>
                                    <Button Command="{Binding Command}" Opacity="0" WidthRequest="0"/>
                                </StackLayout>
                            </DataTemplate>
                        </CollectionView.ItemTemplate>
                    </CollectionView>
                </StackLayout>
            </Frame>
        </ContentView.Content>
    </ContentView>
    
  3. 在页面中集成菜单并动态更新
    在你的页面布局里加入这个自定义菜单,再放一个汉堡按钮控制显示/隐藏,然后在页面的生命周期方法里更新菜单项:

    <Grid>
        <!-- 页面主内容 -->
        <ScrollView>
            <!-- 这里放你的页面实际内容 -->
        </ScrollView>
    
        <!-- 侧边菜单,默认隐藏在屏幕左侧 -->
        <controls:CustomFlyoutMenu x:Name="PageFlyoutMenu"
                                   BindingContext="{Binding Source={RelativeSource AncestorType={x:Type viewmodels:GlobalMenuViewModel}}}"
                                   TranslationX="-280"/>
    
        <!-- 汉堡按钮 -->
        <Button ImageSource="hamburger.png"
                BackgroundColor="Transparent"
                HorizontalOptions="Start"
                VerticalOptions="Start"
                Margin="15"
                Command="{Binding ToggleMenuCommand}"/>
    </Grid>
    

    然后在页面的ViewModel里,当页面显示时替换菜单内容:

    protected override void OnAppearing()
    {
        base.OnAppearing();
        // 获取全局菜单视图模型(可以用依赖注入或者静态实例)
        var globalMenu = App.Current.Services.GetService<GlobalMenuViewModel>();
        
        // 清空原有菜单,添加当前页面专属的菜单项
        globalMenu.MenuItems.Clear();
        globalMenu.MenuItems.Add(new MenuItemModel 
        { 
            Title = "页面A专属选项1", 
            Icon = "icon1.png",
            Command = new Command(() => { /* 执行对应操作 */ })
        });
        globalMenu.MenuItems.Add(new MenuItemModel 
        { 
            Title = "页面A专属选项2", 
            Icon = "icon2.png",
            Command = new Command(() => { /* 执行对应操作 */ })
        });
    }
    

    最后在GlobalMenuViewModel里实现菜单的显示/隐藏逻辑:

    public class GlobalMenuViewModel : ObservableObject
    {
        public ObservableCollection<MenuItemModel> MenuItems { get; set; } = new();
        
        private double _menuTranslationX = -280;
        public double MenuTranslationX
        {
            get => _menuTranslationX;
            set => SetProperty(ref _menuTranslationX, value);
        }
    
        public ICommand ToggleMenuCommand => new Command(() =>
        {
            MenuTranslationX = MenuTranslationX == -280 ? 0 : -280;
        });
    }
    

二、借助社区工具包的Drawer控件

如果你不想从零写布局,可以用MAUI Community Toolkit里的Drawer控件,它已经封装好了抽屉的展开/收起逻辑,你只需要动态绑定菜单项即可:

  • 在页面布局中用Drawer包裹主内容和菜单区域
  • 同样在页面OnAppearing时更新菜单绑定的数据源
  • 通过控件自带的IsOpen属性控制菜单显示

这种方式更快捷,适合追求开发效率的场景。

注意事项

  • 所有UI更新操作一定要在主线程执行,避免跨线程异常
  • 如果需要全局统一的菜单状态,可以把GlobalMenuViewModel注册为单例,确保所有页面共享同一个菜单实例

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.21 07:03:02