编辑:包含代码片段
MAUI 的 XAML 非常冗长,只是好奇是否有一种方法可以为通用类型的转换器编写更短的语法。看看下面的截图。我必须写这么多(注释掉)才能达到想要的结果。
如果我对每个项目都使用注释掉的语法,XAML 文件将会非常长。如果我为特定类型创建 Converter 类,那么我必须为不同类型多次编写/重复同一个类,以实现更短的 XAML。
当前语法
<ImageButton.CommandParameter>
<Binding>
<Binding.Converter>
<conv:ItemToMenuItemConverter x:TypeArguments="model:Item" MyView="{x:Reference optionsLayout}" />
</Binding.Converter>
<Binding.ConverterParameter>
<x:Static>helpers:ListOption.TOGGLE</x:Static>
</Binding.ConverterParameter>
</Binding>
</ImageButton.CommandParameter>
所需语法
<Image CommandParameter="{conv:ItemToMenuItemConverter Menu=TOGGLE, MyView="{x:Reference optionsLayout}"}" x:TypeArguments="model:Item" />
ItemToMenuItemConverter
是一个Generic类,因此我无法实现所需的语法。您现在可以查看图像以了解问题所在。
您的问题是是否有一种方法可以为具有通用类型的转换器编写更短的语法。您的代码(据我所知)描述了通过识别通用类型将按钮映射到命令的努力。但映射可以通过更简单的机制来实现,其中任何给定的泛型类型都可以在其构造函数中指定命令映射。这就是我的意思。
假设您有大量
Button
(如此处所示)或 ImageButton
或其他。第一件事是制作控件的自定义版本,并为其指定静态属性 Dictionary<string, ICommand>
。本质上,这仍然是一个“转换器”,因为它将 CommandParameter
直接映射到 ICommand
。
using System.Windows.Input;
namespace dictionary_button.Controls;
public partial class DictionaryCommandButton : Button
{
public static Dictionary<string, ICommand> Commands = new Dictionary<string, ICommand>();
public DictionaryCommandButton()
{
BindingContext = this;
HandleCommand = new Command<string>(OnHandle);
}
public ICommand HandleCommand { get; private set;}
private async void OnHandle(string key)
{
if (Commands.TryGetValue(key, out ICommand? command))
{
command?.Execute(this);
}
else
{
await App.Current.MainPage.DisplayAlert(
title: "Error",
message: "Command not in dictionary",
cancel: "Got it");
}
}
}
这里的目标是简化您的 xaml 语法,现在看起来像这样:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:dictionary_button.Controls"
x:Class="dictionary_button.MainPage">
<ScrollView>
<VerticalStackLayout
Padding="30,0"
Spacing="25">
<Image
Source="dotnet_bot.png"
HeightRequest="185"
Aspect="AspectFit"
SemanticProperties.Description="dot net bot in a race car number eight" />
<HorizontalStackLayout HorizontalOptions="CenterAndExpand" Spacing="10">
<controls:DictionaryCommandButton Text="▲" Command="{Binding HandleCommand}" CommandParameter="Main.Up"/>
<controls:DictionaryCommandButton Text="▼" Command="{Binding HandleCommand}" CommandParameter="Main.Down"/>
<controls:DictionaryCommandButton Text="►" Command="{Binding HandleCommand}" CommandParameter="Main.Right"/>
<controls:DictionaryCommandButton Text="◄" Command="{Binding HandleCommand}" CommandParameter="Main.Left"/>
</HorizontalStackLayout>
</VerticalStackLayout>
</ScrollView>
</ContentPage>
现在,由于您可以从
View
、泛型类型构造函数、从“任何地方”添加命令,因此您可以从一开始就设置命令。此示例中的命令很简单,但并非必须如此。例如,视图模型中的命令实现可能会在最终执行上下文相关操作之前动态检查其他菜单或复选框的值。但这应该给你一个想法:
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
// ANY view or type can preload its commands into the static dictionary.
DictionaryCommandButton.Commands["Main.Up"] = DisplayUp;
DictionaryCommandButton.Commands["Main.Down"] = DisplayDown;
DictionaryCommandButton.Commands["Main.Left"] = DisplayLeft;
DictionaryCommandButton.Commands["Main.Right"] = DisplayRight;
}
ICommand DisplayUp { get; } = new Command(async() =>
{
await App.Current.MainPage.DisplayAlert(
title: "Handled!",
message: "You clicked Up",
cancel: "Got it");
});
ICommand DisplayDown { get; } = new Command(async () =>
{
await App.Current.MainPage.DisplayAlert(
title: "Handled!",
message: "You clicked Down",
cancel: "Got it");
});
ICommand DisplayLeft { get; } = new Command(async () =>
{
await App.Current.MainPage.DisplayAlert(
title: "Handled!",
message: "You clicked Left",
cancel: "Got it");
});
ICommand DisplayRight { get; } = new Command(async () =>
{
await App.Current.MainPage.DisplayAlert(
title: "Handled!",
message: "You clicked Right",
cancel: "Got it");
});
}
我希望这对你有帮助。