Uno平台Silverlight迁移指南:对话框与错误处理机制详解

Uno平台Silverlight迁移指南:对话框与错误处理机制详解

uno uno 项目地址: https://gitcode.com/gh_mirrors/uno/Uno

引言

在Silverlight向Uno平台迁移过程中,对话框和错误处理是需要重点关注的组件。本文将深入探讨如何在Uno平台中实现Silverlight的对话框功能,特别是ChildWindow控件的替代方案,并介绍如何构建健壮的对话框管理和错误处理机制。

对话框基础概念

对话框是模态UI覆盖层,用于提供上下文应用信息。它会阻止与应用程序窗口的交互,直到用户明确关闭它。在Silverlight中常用的ChildWindow控件,在UWP/Uno平台中对应的替代方案是ContentDialog。

ContentDialog是一个灵活的控件,可以包含复选框、超链接、按钮和任何其他XAML内容。它既可以通过代码创建,也可以作为新项目项添加,并支持完整的设计器功能。

ContentDialog的重要限制

关键限制:每个线程同一时间只能打开一个ContentDialog。尝试同时打开两个ContentDialog会抛出异常,即使它们试图在不同的AppWindows中打开。

由于UWP环境支持异步操作,应用程序的不同部分可能同时尝试显示ContentDialog。虽然在开发和测试过程中可能不会出现冲突,但在生产环境中可能会出现意外情况。为防止这种情况,建议使用管理器确保一次只显示一个实例,其他实例按顺序排队显示。

构建对话框管理器

DialogManager类实现

我们创建一个DialogManager类,使用SemaphoreSlim类确保一次只有一个显示函数在执行:

internal static class DialogManager
{
    private static readonly SemaphoreSlim _oneAtATimeAsync = new SemaphoreSlim(1, 1);

    internal static async Task<T> OneAtATimeAsync<T>(
        Func<Task<T>> show, 
        TimeSpan? timeout, 
        CancellationToken? token)
    {
        var to = timeout ?? TimeSpan.FromHours(1);
        var tk = token ?? new CancellationToken(false);
        
        if (!await _oneAtATimeAsync.WaitAsync(to, tk))
        {
            throw new Exception($"{nameof(DialogManager)}.{nameof(OneAtATimeAsync)} has timed out.");
        }
        
        try
        {
            return await show();
        }
        finally
        {
            _oneAtATimeAsync.Release();
        }
    }
}

技术要点解析

  1. SemaphoreSlim:用于限制可以访问资源的线程数,这里设置为1确保一次只有一个对话框显示
  2. WaitAsync:异步等待信号量可用,支持超时和取消令牌
  3. 异常处理:使用try-finally确保信号量总是被释放
  4. 参数说明
    • show:实际显示对话框的方法
    • timeout:等待超时时间
    • token:取消令牌

对话框扩展方法

为简化ContentDialog的使用,我们创建了一系列扩展方法:

internal static class DialogExtensions
{
    internal static async Task<ContentDialogResult> ShowOneAtATimeAsync(
        this ContentDialog dialog,
        TimeSpan? timeout = null,
        CancellationToken? token = null)
    {
        return await DialogManager.OneAtATimeAsync(
            async () => await dialog.ShowAsync(), 
            timeout, 
            token);
    }

    // 简化按钮设置的扩展方法
    internal static ContentDialog SetPrimaryButton(this ContentDialog dialog, string text)
    {
        dialog.PrimaryButtonText = text;
        dialog.IsPrimaryButtonEnabled = true;
        return dialog;
    }

    // 其他按钮设置方法...
}

使用示例

var errorDialog = new ContentDialog
{
    Title = "错误标题",
    Content = "错误内容"
}.SetPrimaryButton("确定");

await errorDialog.ShowOneAtATimeAsync();

错误对话框处理

结合上述类和额外辅助工具,我们可以简化错误对话框的显示:

internal static class ErrorDialogHelper
{
    internal static async Task ShowErrorAsync(string titleResourceKey, string contentResourceKey)
    {
        await CoreApplication.MainView.Dispatcher.RunAsync(
            Windows.UI.Core.CoreDispatcherPriority.Normal, 
            async () =>
            {
                var errorWindow = new ContentDialog
                {
                    Title = GetResource(titleResourceKey),
                    Content = GetResource(contentResourceKey)
                }.SetPrimaryButton("确定");
                
                await errorWindow.ShowOneAtATimeAsync();
            });
    }

    internal static async Task ShowFatalErrorAsync<TErrorPage>(
        string titleResourceKey, 
        string contentResourceKey)
        where TErrorPage : Page, new()
    {
        await CoreApplication.MainView.Dispatcher.RunAsync(
            Windows.UI.Core.CoreDispatcherPriority.Normal, 
            async () =>
            {
                var errorDialog = new ContentDialog
                {
                    Title = GetResource(titleResourceKey),
                    Content = GetResource(contentResourceKey)
                }.SetPrimaryButton("退出应用");
                
                await errorDialog.ShowOneAtATimeAsync();

                // 致命错误处理
                #if __WASM__
                    Window.Current.Content = new TErrorPage();
                #else
                    Application.Current.Exit();
                #endif
            });
    }
}

使用场景分析

  1. 普通错误:使用ShowErrorAsync显示非致命错误
  2. 致命错误:使用ShowFatalErrorAsync显示致命错误,并根据平台执行不同操作:
    • WASM平台:替换为错误页面
    • 其他平台:退出应用

最佳实践建议

  1. 线程安全:始终通过Dispatcher在主线程上创建和显示对话框
  2. 资源管理:使用资源键而非硬编码字符串,便于本地化
  3. 错误分类:区分普通错误和致命错误,采取不同处理策略
  4. 日志记录:在显示错误对话框前记录错误信息,便于问题追踪

总结

在Uno平台中实现Silverlight的对话框功能需要特别注意线程安全和并发控制。通过构建DialogManager和配套的扩展方法,我们可以创建健壮、易用的对话框系统。错误处理机制则确保了应用在异常情况下仍能提供良好的用户体验。

这种模式不仅适用于从Silverlight迁移的场景,也是任何Uno/UWP应用中处理对话框和错误的良好实践。

uno uno 项目地址: https://gitcode.com/gh_mirrors/uno/Uno

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

章瑗笛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值