在我的MAUI应用程序中,我在两个页面之间导航,主页面和添加页面。
我正在按钮调用的ViewModel上的命令中使用await Shell.Current.GoToAsync()
。但是,当我单击按钮时,它保持灰色。它导航到正确的页面,但当我返回到页面时,它仍然是灰色的。如果我右键单击按钮,它会修复此问题,不再是灰色的。如果我取消await
或使其不同步,也会修复此问题。
第一节第一节第一节第一节第一节第二节第一节
<?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"
xmlns:viewmodel="clr-namespace:ButtonTest"
x:DataType="viewmodel:MainPageViewModel"
x:Class="ButtonTest.MainPage">
<ScrollView>
<VerticalStackLayout
Spacing="25"
Padding="30,0"
VerticalOptions="Center">
<Image
Source="dotnet_bot.png"
SemanticProperties.Description="Cute dot net bot waving hi to you!"
HeightRequest="200"
HorizontalOptions="Center" />
<Label
Text="Hello, World!"
SemanticProperties.HeadingLevel="Level1"
FontSize="32"
HorizontalOptions="Center" />
<Label
Text="Welcome to .NET Multi-platform App UI"
SemanticProperties.HeadingLevel="Level2"
SemanticProperties.Description="Welcome to dot net Multi platform App U I"
FontSize="18"
HorizontalOptions="Center" />
<Button
x:Name="CounterBtn"
Text="AddPage"
Command="{Binding GoAddPageCommand}"
HorizontalOptions="Center" />
</VerticalStackLayout>
</ScrollView>
</ContentPage>
namespace ButtonTest;
public partial class MainPage : ContentPage
{
int count = 0;
public MainPage(MainPageViewModel vm)
{
InitializeComponent();
BindingContext= vm;
}
private void OnCounterClicked(object sender, EventArgs e)
{
count++;
if (count == 1)
CounterBtn.Text = $"Clicked {count} time";
else
CounterBtn.Text = $"Clicked {count} times";
SemanticScreenReader.Announce(CounterBtn.Text);
}
}
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ButtonTest
{
public partial class MainPageViewModel : ObservableObject
{
[RelayCommand]
public async Task GoAddPage()
{
await Shell.Current.GoToAsync("//AddPage");
}
}
}
<?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"
xmlns:viewmodel="clr-namespace:ButtonTest"
x:DataType="viewmodel:AddPageViewModel"
x:Class="ButtonTest.AddPage"
Title="AddPage">
<VerticalStackLayout>
<Button
x:Name="CounterBtn"
Text="MainPage"
Command="{Binding GoMainPageCommand}"
HorizontalOptions="Center" />
</VerticalStackLayout>
</ContentPage>
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ButtonTest
{
public partial class AddPageViewModel : ObservableObject
{
[RelayCommand]
public async Task GoMainPage()
{
await Shell.Current.GoToAsync("//MainPage");
}
}
}
Appshell.xaml
<Shell
x:Class="ButtonTest.AppShell"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:ButtonTest"
Shell.FlyoutBehavior="Disabled">
<ShellContent
Title="MainPage"
ContentTemplate="{DataTemplate local:MainPage}"
Route="MainPage" />
</Shell>
AppShell.xaml.cs
public partial class AppShell : Shell
{
public AppShell()
{
InitializeComponent();
Routing.RegisterRoute($"{nameof(MainPage)}", typeof(MainPage));
Routing.RegisterRoute($"{nameof(AddPage)}", typeof(AddPage));
}
}
我认为按下按钮后它会返回正常颜色。我尝试删除async
或不返回Task
,效果如预期。如何处理异步命令和按钮?
3条答案
按热度按时间yqlxgs2m1#
当您使用
[RelayCommand]
属性为方法自动生成Command
时,将生成何种类型的Command
取决于方法的返回类型和签名。1.中继命令
当你的方法有一个
void
返回类型时,那么一个RelayCommand
会在幕后为你生成:这里会生成一个
RelayCommand
,由于方法是void
,所以不能等待它的执行,它会同步运行,所以命令会立即返回,按钮也会立即重新启用。2.异步中继命令
另一方面,当你的方法返回类型是
async Task
时,它会在幕后创建一个AsyncRelayCommand
:这里有几个关键的区别:
AsyncRelayCommand
等待执行任务1.在等待执行时,
AsyncRelayCommand
的IsRunning
标志将设置为true
1.当
IsRunning
标志为true
时,MAUI中的按钮识别AsyncRelayCommands
并被禁用,而同步RelayCommand
的情况并非如此在这种情况下,您的Button将保持禁用状态,直到
Shell.Current.GoToAsync();
调用完成执行。这可能需要很长时间,具体取决于您的应用中正在执行的操作。快速修复
除非您需要特别等待导航调用,否则您只需更改方法签名以返回
void
,而不是上面第1节中的Task
。* 请注意,这意味着您的方法在直接调用时不可等待。*一般备注
我建议不要直接在ViewModel中执行导航。我个人认为,最好将导航隐藏在接口后面,或者将其委托给视图的代码。这样,ViewModel就可以保持整洁和可测试性。
至于为什么Button永远不会返回到它的活动颜色,可能有一个bug,尽管我还没有遇到过。对我来说,它在我的MAUI应用程序中工作得很好。但是,我总是把导航委托给我的视图或我的ViewModels之外的一个helper类。
ttygqcqt2#
默认情况下,async RelayCommand将禁用该按钮,直到命令的Task完成。您在此处描述的行为表明
await Shell.Current.GoToAsync()
未完成,这可能是一个bug。您可以通过在GoToAsync()
之后放置断点并检查在AddPage显示后是否命中断点来验证这一点。flmtquvp3#
您可以将方法更改为下面的代码。
使用async方法使按钮必须等待,所以它不能完成任务,直到你把它转回主线程。所以这就是为什么颜色不能改回来。你可以使用静态方法。