XAML .Net Maui -如何返回根页面

wlp8pajw  于 2022-12-07  发布在  .NET
关注(0)|答案(3)|浏览(370)

我觉得我只是没有直接问谷歌霸主这个问题,所以我想看看是否有人能帮助解释如何做到这一点。我有一个新的.Net毛伊岛应用程序,使用4个不同的视图/页面。我创建的主页(根)让我从我们的数据库搜索用户,然后转换到一个新的页面;我称之为ResultsPage。在那里,您可以选择一个用户并被带到DetailPage,在那里可以执行编辑。一旦您进行了编辑并保存,它会将您发送到我的最后一个页面(SuccessPage),其中包含有关更改的消息。
这一切都很有魅力。我可以使用ViewModels和QueryProperties将数据传递到页面,并将更改保存到数据库。失败的地方是在SuccessPage上。在您收到有关更新的消息后,我希望有一个按钮,用户可以直接返回到MainPage,执行新的搜索并重复以上所有步骤。
对于所有其他页面转换,我可以利用Shell.Current.GoToAsync()来访问新页面和/或传递数据,如下所示:

await Shell.Current.GoToAsync(nameof(ResultsPage));

await Shell.Current.GoToAsync($"{nameof(DetailsPage)}?Parameter={param}");

在Success页面中,我尝试输入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屏幕截图:

  • 单击按钮之前 * x1c 0d1x
  • 单击按钮后 *

主页添加编辑

  • 主页面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更新

我创建了一个repo,其中托管了应用程序的简化版本,该版本重复了此问题:GitHub

编辑日期:2022年10月6日

由于其他人的建议,我已经为此问题在Maui GitHub上打开了一个新的问题。要查看该问题并跟踪其进度,请转到here

ltqd579y

ltqd579y1#

我已经创建了一个新的示例进行测试,并尝试使用await Shell.Current.Navigation.PopToRootAsync();await Shell.Current.GoToAsync($"//{nameof(MainPage)}");导航到根页面。它们都显示了主页的标题,但没有显示页面的内容。
所以我点击了工具栏上的按钮,看到了实时的可视化树,当我回到主页面时,发现里面只有主页面。然后我试着在android平台上运行它,它工作正常。这应该是用户在windows平台上进入根页面时的显示错误。
你可以试着在github上向毛伊岛报告。

ujv3wf0j

ujv3wf0j2#

当你得到“当前不支持的shell元素的相对路由”时,10种情况中有9种,你忘记了将它添加到你的shell中或注册它。
在AppShell.xaml中,您需要具有页面 shell 内容的 shell 项。在AppShell.xaml.cs中,您需要路由。RegisterRoute(..)
然后您将能够使用“//"调用导航。
试试看。
编辑:只是在同一个页面上,这不会神奇地清除你的UI。当你导航到它时,页面不会被重建。

niwlg2el

niwlg2el3#

所以我能够直接从微软支持部门得到一些关于这个问题的帮助。他们的支持建议我尝试在xaml代码隐藏中使用以下内容弹出到根页面:

while (Navigation.NavigationStack.Count > 1)
{
    Navigation.RemovePage(Navigation.NavigationStack[1]);
}

await dispatcherProvider.DispatchAsync(() => Shell.Current.GoToAsync(".."));

while循环遍历导航堆栈中的页面,并在使用GoToAsync()的调度程序之前逐个删除它们。除了在事件处理程序中包含上述代码之外,还需要在构造函数中添加以下内容作为全局变量和赋值:

private readonly IDispatcher dispatcherProvider;
public ActionPage(ActionViewModel vm, IDispatcher dispatcher)
{
    BindingContext = vm;
    dispatcherProvider = dispatcher;
    InitializeComponent();
}

支持人员和我都认为文档在执行这样一个简单的功能需要 * 什么 * 上是令人困惑的。但是这个解决方案至少也按照我需要的方式工作了,希望能帮助那些发现自己处于同样困境的人

相关问题