在 MAUI 中创建动态菜单系统的最佳方法是什么?

问题描述 投票:0回答:1

我对 MAUI 完全陌生,正在尝试创建一个应用程序,该应用程序在用户登录时检索他们有权访问的所有菜单项,并为每个菜单项创建一个“按钮”,单击该按钮时会直接进入该视图,或者如果它是一个子视图-menu 它指向该菜单并最终链接到最终视图。我目前有一个工作演示,使用 CollectionView 在边框内显示列表中的每个项目,使其具有按钮外观,但边框没有悬停或单击状态,因此我无法复制单击的外观一个按钮。在深入研究之后,我质疑 CollectionView 方法是否是正确的方法。

这是我的xaml:

<?xml version="1.0" encoding="utf-8" ?>
    <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 x:Class="GppScanMaui.Menu.MenuPage"
                 x:Name="CurrentMenuPage">
        <CollectionView x:Name="MenuItemList"
                        BindingContext="{x:Reference CurrentMenuPage}"
                        ItemsSource="{Binding MenuItemListData}"
                        ItemsLayout="VerticalList"
                        SelectionMode="Single"
                        SelectionChanged="OnCollectionViewSelectionChanged"
                        EmptyView="No access available">
            <CollectionView.ItemTemplate>
                <DataTemplate>
                    <Border Margin="50, 10"
                            Padding="0, 10"
                            Stroke="#2B0B98"
                            StrokeThickness="4"
                            StrokeShape="RoundRectangle 10,10,10,10" >
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width=".2*" />
                                <ColumnDefinition Width=".8*" />
                            </Grid.ColumnDefinitions>
    
                            <Image Source="cpi_browser_logo.ico" Grid.Column="0" Grid.Row="0" />
    
                            <VerticalStackLayout Grid.Column="1" Grid.Row="0" Padding="10" VerticalOptions="Center" HorizontalOptions="Fill">
                                <Label Text="{Binding Text}" FontSize="Medium" FontAttributes="Bold" TextColor="{AppThemeBinding Dark={StaticResource White}, Light={StaticResource Black}, Default={StaticResource Black}}"/>
                                <Label Text="{Binding Description}" FontAttributes="Italic" TextColor="{AppThemeBinding Dark={StaticResource White}, Light={StaticResource Black}, Default={StaticResource Black}}"/>
                            </VerticalStackLayout>
    
                        </Grid>
                    </Border>
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>
    
    </ContentPage>

这是我的 xaml.cs:

using System.Collections.ObjectModel;
using GppScanMaui.Clients;

namespace GppScanMaui.Menu;

[QueryProperty(nameof(MenuToLoad), "menuToLoad")]
public partial class MenuPage : ContentPage
{
    public IReadOnlyList<ScanMenuItem>? MenuItems { get; private set; }

    public ObservableCollection<ScanMenuItem> MenuItemListData { get; } = new ObservableCollection<ScanMenuItem>();

    public string MenuToLoad { private get; set; } = "Main";

    public MenuPage()
    {
        InitializeComponent();
    }

    protected override void OnNavigatedTo(NavigatedToEventArgs args) {
        if (Menus.MenuItems.TryGetValue(MenuToLoad, out var menuItems)) {
            MenuItems = menuItems.SubMenuItems;
            Title = menuItems.Text;
        }
        else {
            MenuItems = new List<ScanMenuItem>();
        }

        var allowedMenuItems = MenuItems.Where(item =>
            // There are no restrictions if there are no allowed groups
            item.AllowedGroups.Count == 0
            // If the user is an admin, they can see everything
            || (User.CurrentUser!.Groups?.Any(g => g == "Admin") ?? false)
            // If the user is in any of the allowed groups, at the specified location, they can see the item
            || item.AllowedGroups.Any(g => (User.CurrentUser!.Groups?.Contains(g.Group) ?? false) && (!g.Location.HasValue || g.Location == User.CurrentUser.Site)));

        MenuItemListData.Clear();
        foreach (var item in allowedMenuItems) {
            MenuItemListData.Add(item);
        }
        base.OnNavigatedTo(args);
    }

    private static void OnCollectionViewSelectionChanged(object sender, SelectionChangedEventArgs e) {
        if (e.CurrentSelection.Count == 0) {
            return;
        }
        var itemName = ((ScanMenuItem)e.CurrentSelection[0]).Name;
        var path = $"""{itemName}?menuToLoad={itemName}""";
        Shell.Current.GoToAsync(path);
        ((CollectionView)sender).SelectedItem = null;
    }
}

这是我的 ScanMenuItem.cs:

namespace GppScanMaui.Menu {
    public class ScanMenuItem {

        public ScanMenuItem(int position, string name, string text, string description, IReadOnlyList<ScanMenuItem>? subMenuItems = null, IReadOnlyList<GroupLocation>? allowedGroups = null) {
            Position = position;
            Name = name;
            Text = text;
            Description = description;
            SubMenuItems = subMenuItems ?? [];
            AllowedGroups = allowedGroups ?? [];
        }

        public int Position { get; }
        public string Name { get; }
        public string Text { get; }
        public string Description { get; }

        public IReadOnlyList<ScanMenuItem> SubMenuItems { get; init; } = [];

        public string DisplayName {
            get { return string.Format("{0} - {1}", Position, Text); }
        }

        public IReadOnlyList<GroupLocation> AllowedGroups { get; init; } = [];
    }
}
maui maui-community-toolkit
1个回答
0
投票

我也做了类似的事情。 我有 contentViews 定义我的“按钮”的外观 - 平铺、圆形、单个全宽度等等。 检索菜单项后,我创建一个包含可能需要的列数的网格,然后循环遍历该网格,根据需要添加行。 对于应占据多于一列的项目,请使用 ColumnSpan。 悬停状态不能很好地转换为移动设备,因为没有鼠标在视图中移动。 您可以在点击项目时更改颜色/阴影以使其具有沮丧的外观,但我没有发现这有用,仅在点击项目时更改视图的内容似乎就足够了。

© www.soinside.com 2019 - 2024. All rights reserved.