我在 .NET 8.0 MAUI 应用程序的 iOS 中遇到 RelayCommand 无法工作 (CommunityToolkit.Mvvm.Input.RelayCommand) 的问题。此 RelayCommand 在 iOS 中无法触发,但在 Windows 和 Android 上运行。这发生在面向 Android、Windows 和 iOS 的 MVVM .NET 8.0 MAUI 应用程序中。
对于打开的屏幕,我使用 ViewModel,其中在构造函数中定义了这些 RelayCommand:
ChangeSettingsCommand = new CommunityToolkit.Mvvm.Input.RelayCommand<Models.ModelLogin>(OnChangeSettings, CanChangeSettings);
ChangeSettingsCommand.NotifyCanExecuteChanged();
ViewModel 中的 OnChangeSettings 和 CanChangeSettings 方法如下:
public CommunityToolkit.Mvvm.Input.RelayCommand<Models.ModelLogin> ChangeSettingsCommand { get; set; }
public bool CanChangeSettings(object paramater)
{
return true;
}
#endregion
internal void OnChangeSettings(object parameter)
{
ChangeSettingsEvent?.Invoke(this, new EventArgs());
}
OnChangeSettings 方法调用视图 (...xaml.cs) 中定义的事件:
moLogin.ChangeSettingsEvent += MoLogin_ChangeSettingsEvent;
private async void MoLogin_ChangeSettingsEvent(object sender, EventArgs e)
{
await Utils.PushAsyncWithoutDuplicate(new InitialSettingsNew(true));
}
在视图中,命令被“设置”为这样的按钮(moLogin 是 ViewModel):
lst.Add(new Controls.Phone.PBImageButton()
{
Command = moLogin.ChangeSettingsCommand,
//BindingContext = moLogin,
//ButtonImageFile = Utils.OnPlatform<string>("Toolbar/settingswhite.png", "settingswhite.png", "Images/White/settings.png"),
Source = "w_settings.png",
//Behaviors.Add(behavior),
BackgroundColor = Colors.Transparent,
ButtonBorderColor = Colors.Transparent,
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.Center,
HeightRequest = 40,
WidthRequest = 40
});
在 PBImageButton (派生自 ImageButton 的自定义控件)的构造函数中,ICommand 设置如下:
public PBImageButton()
{
this.CornerRadius = 0;
this.BackgroundColor = Colors.Transparent;
this.Padding = new Thickness(5);
SetupGrid();
TapGestureRecognizer t = new TapGestureRecognizer();
this.GestureRecognizers.Add(new TapGestureRecognizer()
{
Command = ExecuteCommand
});
}
PBImageButton 的 ExecuteCommand (ICommand) 属性如下:
private ICommand ExecuteCommand
{
get
{
return new Command(async () =>
{
if (this.IsEnabled)
{
await this.ScaleTo(0.8, 50, Easing.Linear);
await Task.Delay(100);
await this.ScaleTo(1, 50, Easing.Linear);
PBImageButtonClicked?.Invoke(this, new EventArgs());
this.Command?.Execute(CommandParameter);
}
}
);
}
}
如果我在 ViewModel 中的 OnChangeSettings 方法中设置断点,则在 Windows 和 Android 中会触发此断点,但在 iOS 上不会触发此方法。 因此,不知何故,PBImageButton 命令(这是一个 System.Windows.Input.ICommand 属性)在 iOS 上不起作用。
我已经尝试过以下方法来解决它:
1.
看起来可能是这个原因: https://github.com/CommunityToolkit/Maui/issues/2065
当 RelayCommand 的名称带有“On”前缀时,该命令 永远不会被触发。
删除“On..”并没有解决问题。
2.
使用 RelayCommand 属性(而不是在 C# 本身中定义 RelayCommand):
[RelayCommand]
internal void ChangeSettings(object parameter)
{
ChangeSettingsEvent?.Invoke(this, new EventArgs());
}
这也没有解决问题。
3.
使用:
ChangeSettings = new CommunityToolkit.Mvvm.Input.RelayCommand<Models.ModelLogin>(OnChangeSettings, CanChangeSettings);
ChangeSettings.NotifyCanExecuteChanged();
代替:
ChangeSettingsCommand = new CommunityToolkit.Mvvm.Input.RelayCommand<Models.ModelLogin>(OnChangeSettings, CanChangeSettings);
ChangeSettingsCommand.NotifyCanExecuteChanged();
这并没有解决问题。
4.
当我直接在视图中使用带有命令绑定的 PBImageButton 时......:
<ucp:PBImageButton Grid.Row="10" Grid.ColumnSpan="2" HorizontalOptions="Fill" Command="{Binding ChangeSettingsCommand}" Margin="0" Padding="0" HeightRequest="30" WidthRequest="30" ButtonText="test" Background="Red"/>
它可以在 Windows 和 Android 上运行,但不能在 iOS 上运行。这也不是解决办法。
5.
在下面的方法中使用“public”而不是“internal”:
public void OnChangeSettings(object parameter)
{
ChangeSettingsEvent?.Invoke(this, new EventArgs());
}
但这也没有解决问题。
我认为这可能是与 .NET 8.0 相关的问题,因为我在另一个与 MAUI .NET 7.0 配合使用的 MAUI 应用程序中使用了相同的代码,而这里没有出现此问题。 有谁知道 iOS 和 .NET 8.0 是否存在有关 RelayCommand (CommunityToolkit.Mvvm.Input.RelayCommand) 的已知问题? 有人知道这里出了什么问题吗?也许这是我忽略的显而易见的事情。
这个问题现在已经解决了。 我使用的 PBImageButton 源自 Microsoft.MAUI.Controls.ImageButton:
public class PBImageButton : ImageButton
{
当我让它从 Microsoft.MAUI.Controls.Image 派生时,它工作正常:
public class PBImageButton : Image
{
它不能与 ImageButton 一起使用的原因可能是因为 TapGestureRecognizer 与 .NET MAUI 8.0 结合使用。这似乎是一个已知问题: https://github.com/dotnet/maui/issues/25237
Image 控件没有 padding 属性,也没有边框颜色属性,但使用 Image 控件代替 ImageButton 控件是一个很好的解决方案。