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