Page.OnAppearing 中的 Xamarin.Forms Page.DisplayAlert [英] Xamarin.Forms Page.DisplayAlert in Page.OnAppearing

查看:27
本文介绍了Page.OnAppearing 中的 Xamarin.Forms Page.DisplayAlert的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我无法在 Xamarin.Forms PageOnAppearing 回调中显示 DisplayAlert 弹出窗口.到目前为止,这是我尝试过的:

protected override void OnAppearing(){base.OnAppearing();this.DisplayAlert("Alert", "认为自己被警告了", "OK");}

考虑到 DisplayAlert 在技术上是一个 async 函数,返回一个 Task,我也尝试了以下方法:

受保护的异步覆盖 void OnAppearing(){base.OnAppearing();await this.DisplayAlert("Alert", "认为自己被警告了", "OK");}

但是,两者似乎都不起作用.我的猜测是,将 OnAppearing 设置为 async 并没有多大意义,因为它不会返回 Task,并且所以这变成了关于调用框架的即发即弃的情况.在这种情况下,DisplayAlert 的扩展名也是如此.所以一方面我真的不希望这会起作用,但万一我错了,是否可以在 OnAppearing 中使用 DisplayAlert?p>

更新

似乎我未能提供一些上下文.我正在使用 Xamarin.Forms Shell 模板;虽然我已经开发了一些超出初始模板的内容,但目前很难说 Shell 本身在多大程度上做出了贡献.另外,我的主要目标平台是 Android.

话虽如此,我能够启动一个空白应用程序模板并在其他新鲜的 MainPage 中尝试上述代码——两者都运行良好.我仍然不知道为什么它们在我的实际应用程序环境中不起作用,所以我将在那里进行一些挖掘并报告任何发现.

解决方案

让我的小实验更进一步,尝试了基本的 Shell 模板应用程序.

将 OP 示例 DisplayAlert 代码添加到主 ItemsPage 代码隐藏不起作用.如果我这样做了,

受保护的异步覆盖 void OnAppearing(){base.OnAppearing();如果(viewModel.Items.Count == 0)viewModel.LoadItemsCommand.Execute(null);await this.DisplayAlert("Alert", "Consider yourself alert", "OK");}

项目会加载,但不会显示对话框.如果我将对话框向上移动,

受保护的异步覆盖 void OnAppearing(){base.OnAppearing();await this.DisplayAlert("Alert", "Consider yourself alert", "OK");如果(viewModel.Items.Count == 0)viewModel.LoadItemsCommand.Execute(null);}

对话框不会显示,项目也不会加载.所以异步执行死了和/或徘徊在天空中的大桶中.

然后我尝试将 DisplayAlert 示例添加到主 AppShell 页面,却发现根本没有调用 OnAppearing 覆盖Shell 类.以下打开的 Shell 问题证实了这一点:[Bug] Shell - OnAppearing 未执行#6486.

最后,作为最后的延伸,我尝试将 DisplayAlert 调用侵入到 ItemsPage.OnAppearingLoadItemsCommand 执行的异步回调中.有点讨厌,因为它将视图传递给视图模型,这首先直接违背了良好的 MVVM --

异步任务 ExecuteLoadItemsCommand(ItemsPage 视图){如果(忙)返回;忙=真;尝试{项目.清除();var items = 等待 DataStore.GetItemsAsync(true);foreach (var item in items){项目.添加(项目);}等待 Device.InvokeOnMainThreadAsync(async () =>await view.DisplayAlert("Alert", "Consider yourself alert", "OK"));}捕捉(例外前){Debug.WriteLine(ex);}最后{忙=假;}}

别用石头砸我.

这似乎没有更好的结果.就像在页面的 OnAppearing 中直接调用 DisplayAlert 一样,执行只需要午休.绑定到 IsBusy 标志的微调器从未停止,因此这表明 finally 块甚至从未被执行.

在这一点上我的一般理解是,目前可以从 Shell 的 ContentPage 完成的异步操作类型存在一些限制.即使是对 DataStore.GetItemsAsyncawaited 调用在此实现中也不是真正的异步,所以我有点怀疑它在给定真正的异步数据库连接的情况下是否真的有效.我已经能够让 DisplayAlert 在正常事件处理程序的上下文中工作,所以我认为这个问题的范围是在 OnAppearing 期间发生的任何初始化逻辑以及它结束的任何内容up 直接调用或调度.其中大部分只是观察性推测,但我可能会将其作为错误转发,除非有人可以提供更完整的分析.

更新(用于关闭、强迫症、文档等)

正如评论所示,我使用的 Xamarin.Forms 版本 (4.2.0) 有一个错误,该错误已在以后的版本中修复.

I am unable to get a DisplayAlert popup to show within the OnAppearing callback of a Xamarin.Forms Page. Here is what I have tried so far:

protected override void OnAppearing()
{
    base.OnAppearing();

    this.DisplayAlert("Alert", "Consider yourself alerted", "OK");
}

Considering DisplayAlert is technically an async function, returning a Task, I have also tried the following:

protected async override void OnAppearing()
{
    base.OnAppearing();

    await this.DisplayAlert("Alert", "Consider yourself alerted", "OK");
}

However, neither seem to work. My guess is it doesn't really make much sense to make OnAppearing to be async at all, since it does not return a Task, and so this turns into a fire-and-forget situation with respect to the calling framework. Same by extension goes for DisplayAlert in this context. So on the one hand I don't really expect this to work at all, but in case I'm wrong, is it possible to use DisplayAlert in OnAppearing?

Update

Seems I failed to provide some context. I'm working from an Xamarin.Forms Shell template; though I have already developed some past the initial template, so it's hard to say at this point to what extent the Shell itself contributes at all. Also, my main target platform is Android.

That all being said, I was able to start a blank app template and try the above code in the otherwise fresh MainPage -- both worked fine. I still do not know why they do not work in my actual application context, so I am going to do some digging there and report back any findings.

解决方案

Took my little experiment one step further and tried the basic Shell template app.

Adding the OP sample DisplayAlert code to the main ItemsPage codebehind did not work. If I did this,

protected async override void OnAppearing()
{
    base.OnAppearing();

    if (viewModel.Items.Count == 0)
        viewModel.LoadItemsCommand.Execute(null);

    await this.DisplayAlert("Alert", "Consider yourself alerted", "OK");
}

the items would load but no dialog would show. If instead I moved the dialog up,

protected async override void OnAppearing()
{
    base.OnAppearing();

    await this.DisplayAlert("Alert", "Consider yourself alerted", "OK");

    if (viewModel.Items.Count == 0)
        viewModel.LoadItemsCommand.Execute(null);
}

the dialog would not show nor would the items load. So the async execution died and/or wandered off into the great big bit bucket up in the sky.

I then tried adding the DisplayAlert sample to the main AppShell page, only to find the OnAppearing override does not get called at all for the Shell class. This was confirmed by the following open Shell issue: [Bug] Shell - OnAppearing not executing #6486.

Finally, just as a final stretch, I tried hacking a call to DisplayAlert into the async callback executed by LoadItemsCommand in ItemsPage.OnAppearing. A bit nasty since it's passing the view into the view-model, which is directly against good MVVM in the first place --

async Task ExecuteLoadItemsCommand(ItemsPage view)
{
    if (IsBusy)
        return;

    IsBusy = true;

    try
    {
        Items.Clear();
        var items = await DataStore.GetItemsAsync(true);
        foreach (var item in items)
        {
            Items.Add(item);
        }

        await Device.InvokeOnMainThreadAsync(async () =>
            await view.DisplayAlert("Alert", "Consider yourself alerted", "OK"));
    }
    catch (Exception ex)
    {
        Debug.WriteLine(ex);
    }
    finally
    {
        IsBusy = false;
    }
}

Don't stone me.

This didn't seem to have any better results. Just like when calling DisplayAlert directly in the page's OnAppearing, the execution just took a lunch break. The spinner bound to the IsBusy flag never stopped, so that indicates the finally block never even got executed.

My general understanding at this point is that there is currently some limitation in the type of async operations that can be done from a Shell's ContentPage. Even the awaited call to DataStore.GetItemsAsync is not truly asynchronous in this implementation, so I somewhat doubt it would actually work given a real, asynchronous database connection. I have been able to get DisplayAlert working in the context of a normal event handler, so I think the issue is scoped to whatever initialization logic goes on during OnAppearing and whatever it ends up directly calling or scheduling. Much of this is just observational speculation, but I may forward this on as a bug, unless someone can offer a more complete analysis.

Update (for closure, OCD, documentation, etc)

As the comments indicate, the version of Xamarin.Forms I was using (4.2.0) had a bug that has been fixed in later versions.

这篇关于Page.OnAppearing 中的 Xamarin.Forms Page.DisplayAlert的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆