【发布时间】:2022-10-18 04:38:12
【问题描述】:
我觉得我只是没有向谷歌霸主提出这个问题,所以我要看看是否有人可以帮助解释如何做到这一点。我有一个新的 .Net Maui 应用程序,它使用 4 个不同的视图/页面。我创建的 MainPage (root) 让我可以从我们的数据库中搜索用户,然后将您转到新页面;我称之为ResultsPage。从那里,您可以选择一个用户并被带到一个可以执行编辑的 DetailPage。进行编辑并保存后,它会将您发送到我的最后一页 (SuccessPage),其中包含有关更改的消息。
这一切都像一个魅力。我可以使用 ViewModels 和 QueryProperties 将数据传递给页面,并将更改保存到数据库中。失败的地方是 SuccessPage。在您收到有关更新的消息后,我想要一个按钮,用户可以在该按钮上直接返回 MainPage,执行新的搜索并重复上述所有步骤。
对于所有其他页面转换,我可以利用 Shell.Current.GoToAsync() 进入新页面和/或传递数据,如下所示:
await Shell.Current.GoToAsync(nameof(ResultsPage));
或者
await Shell.Current.GoToAsync($"{nameof(DetailsPage)}?Parameter={param}");
在成功页面中,我尝试输入await Shell.Current.GoToAsync(nameof(MainPage));,但这会引发“相对路由到当前不支持的 shell 元素”的异常,并建议我尝试在我的 uri 中添加 /// 前缀。我尝试过,但唯一改变的是页面标题;它实际上并没有恢复 MainPage UI 元素。那么我怎样才能让 shell 回到 MainPage 呢?
此外,我也尝试过await Shell.Current.Navigation.PopToRootAsync();,但遇到了同样的问题,就像我在 uri 前面加上斜杠时一样;它会更改标题但不会更改任何 UI 元素
编辑
作为参考,这里是按钮背后的代码(注意:我留下了我注释掉的尝试,旁边有注释显示它们如何没有帮助
private async void ReturnSearchButton_Clicked(object sender, EventArgs e)
{
//await Shell.Current.GoToAsync("../"); //exception, ambiguous routes matched
//List<Page> previousPages = Navigation.NavigationStack.ToList();
//foreach (Page page in previousPages)
//{
// Navigation.RemovePage(page); //exception, null value
//}
await Shell.Current.Navigation.PopToRootAsync();
}
这是单击按钮之前和之后的一些 UI 屏幕截图:
主页添加编辑
主页 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="UserNameReset.Views.MainPage"
Title="Home">
<VerticalStackLayout Padding="10"
Margin="5">
<Label
Text="Reset Users"
SemanticProperties.HeadingLevel="Level1"
FontSize="32"
HorizontalOptions="Center" />
<Label
Text="Enter the users email address or their ID with Pin"
SemanticProperties.HeadingLevel="Level3"
HorizontalOptions="Center"
FontSize="18"/>
<Label
x:Name="fullWarningLabel"
SemanticProperties.HeadingLevel="Level3"
HorizontalOptions="Center"
FontSize="18"
TextColor="Red"
Text="You must provide either the users email OR their ID and pin"
IsVisible="false"/>
<Entry
x:Name="emailEntry"
Placeholder="example@demo.org"
ClearButtonVisibility="WhileEditing"
Completed="Entry_Completed"
Keyboard="Email"
IsSpellCheckEnabled="False"/>
<Label
Text="OR"
SemanticProperties.HeadingLevel="Level3"
HorizontalOptions="Center"
FontSize="18"/>
<Grid ColumnDefinitions="*,*" ColumnSpacing="4" RowDefinitions="*,*" RowSpacing="2">
<Entry
x:Name="idEntry"
Placeholder="ID"
ClearButtonVisibility="WhileEditing"
Grid.Column="0"
Completed="Entry_Completed"
IsSpellCheckEnabled="False"/>
<Label
x:Name="idWarning"
IsVisible="false"
Text="Please enter the users ID"
Grid.Column="0"
Grid.Row="2"
TextColor="Red"/>
<Entry
x:Name="pinEntry"
Placeholder="PIN"
ClearButtonVisibility="WhileEditing"
Grid.Column="2"
Completed="Entry_Completed"
IsSpellCheckEnabled="False"/>
<Label
x:Name="pinWarning"
IsVisible="false"
Text="Please enter the users PIN"
Grid.Column="2"
Grid.Row="2"
TextColor="Red"/>
</Grid>
<Button
x:Name="SubmitButton"
Text="Search"
SemanticProperties.Hint="Click to search for the user by values you provided"
Clicked="Entry_Completed"
HorizontalOptions="Center"/>
</VerticalStackLayout>
</ContentPage>
后面的 MainPage 代码
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using UserNameReset.Models;
namespace UserNameReset.Views;
public partial class MainPage : ContentPage
{
readonly ILogger<MainPage> _logger;
public MainPage(ILogger<MainPage> logger)
{
InitializeComponent();
_logger = logger;
}
/// <summary>
/// Triggered when the user clicks the "Search" button,
/// when they finish entering an email,
/// or when they successfully enter both Id and Pin
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void Entry_Completed(object sender, EventArgs e)
{
_logger.LogInformation("Entry fields filled, checking values...");
// Cleans up layout each time search is triggered
pinWarning.IsVisible = false;
idWarning.IsVisible = false;
fullWarningLabel.IsVisible = false;
bool validUser = false;
bool usingPinAndId = false;
Queried_User user = new();
// Check that both the plant ID and PIN were provided
if (!string.IsNullOrWhiteSpace(idEntry.Text) && !string.IsNullOrWhiteSpace(pinEntry.Text))
{
_logger.LogInformation("Pin and ID provided!");
validUser = true;
usingPinAndId = true;
user.Pin = pinEntry.Text;
user.Id = idEntry.Text;
}
// Check if the email was provided (only if the plant ID and PIN weren't)
else if (!string.IsNullOrWhiteSpace(emailEntry.Text))
{
_logger.LogInformation("Email provided!");
validUser = true;
user.Email = emailEntry.Text;
}
// If nothing was provided, add a warning to the appropriate entry fields
else
{
if (!string.IsNullOrWhiteSpace(plantIdEntry.Text))
pinWarning.IsVisible = true;
else if (!string.IsNullOrWhiteSpace(pinEntry.Text))
idWarning.IsVisible = true;
else
fullWarningLabel.IsVisible = true;
}
// Did we get a valid user obj? Navigate to the results page if so
if (validUser)
{
// create a message of how the search is proceeding, changing text depending on search method
string msg = "Searching via " + (usingPinAndId ? "plant ID: (" + user.Id + ") and pin: (" + user.Pin + ")" : "email: (" + user.Email + ")");
_logger.LogInformation("User info validated. Going to get results from DB. " + msg);
GoToResults(msg, user);
}
// Useful for displaying alerts or messages to the end user!!
//await Shell.Current.DisplayAlert("Error!", $"Undable to return records: {ex.Message}", "OK");
}
/// <summary>
/// Takes a simple user object and then redirects the user to the results page,
/// passing the user object as a query property
/// </summary>
/// <param name="user"></param>
private async void GoToResults(string srchMthd, Queried_User user)
{
_logger.LogInformation($"User properties - email:{user.Email} - pin:{user.Pin} - ID:{user.Id}");
await Shell.Current.GoToAsync($"{nameof(ResultsPage)}?SearchMethod={srchMthd}",
new Dictionary<string, object>
{
["User"] = user
});
}
}
GitHub 更新
我创建了一个存储库,其中托管了重复此问题的应用程序的简化版本:GitHub
编辑 2022-10-6
由于其他人的建议,我为这个问题在 Maui GitHub 上打开了一个新问题。要查看该问题并关注其进展,请转到 here
【问题讨论】:
-
让我理解你,你需要 popToRootAsync 但你的主页有一个新实例吗? ui上没有变化吗?
-
我相信是这样,如果我 popToRootAsync,我希望主页中的 UI 元素显示出来。它现在所做的只是更改顶部的标题,但保留上一页(成功页面)的 UI
-
您的 MainPage 和 Shell 之间的关系是什么?您的 AppShell.xaml 是如何定义的?
-
MainPage 是 xaml 端的 AppShell 中列出的唯一一个(作为 ShellContent)。其他三个页面在 AppShell 构造函数中定义如下:
Routing.RegisterRoute(nameoff(ResultsPage), typeof(ResultsPage));。让我知道上面的 sn-ps 是否有益 -
请将此作为 GitHub 上的问题报告给 MAUI 团队,因为它看起来像一个错误。很高兴你有一个回购,你也应该在问题中提供链接。只需转到github.com/dotnet/maui/issues 并使用错误报告模板创建一个新问题