Avalonia学习实践(三)--一个对话框引发的惨案

本文讲述了在Avalonia框架中遇到的跨平台兼容性问题,特别是OpenFileDialog在Windows和统信UOS上的差异。作者详细分析了UI渲染库、MVVM模式和线程管理可能造成的影响,并介绍了Avalonia的日志跟踪和异常处理机制。最终,通过调整代码的异步处理解决了问题。
摘要由CSDN通过智能技术生成

跨平台开发最令人头疼的是在一个平台上能正常运行,换到另外一个平台就不行了,尤其是那些细小的功能,来回的代码修改、重新编译、发布运行着实令人崩溃。


在桌面操作系统中,对文件的选择、查找是很常见的操作,因此系统对话框算是一个桌面UI库最基本的需求了。来看看通过解决一个小小对话框的问题又学到了什么。

1.Avalonia中的系统对话框

Avalonia中的系统对话框都是派生自抽象类SystemDialog,位于Avalonia.Controls命名空间下,公共属性有Title“标题”。文件操作相关的对话框都派生自抽象类FileSystemDialog,公共属性为初始路径。
在这里插入图片描述
以打开文件对话框OpenFileDialog为例,可以设置初始文件名称、文件类型过滤器、是否可选多个文件;打开对话框的方法为ShowAsync(),输入参数为对话框的父级窗口,必填;返回参数为字符串数组,即选中文件的完整路径的集合,如果取消选择则返回null。
ShowAsync(Window parent)的实现为:

/// <summary>
/// Shows the open file dialog.
/// </summary>
/// <param name="parent">The parent window.</param>
/// <returns>
/// A task that on completion returns an array containing the full path to the selected
/// files, or null if the dialog was canceled.
/// </returns>
public Task<string[]?> ShowAsync(Window parent)
{
    if(parent == null)
        throw new ArgumentNullException(nameof(parent));
    var service = AvaloniaLocator.Current.GetService<ISystemDialogImpl>() ??
        throw new InvalidOperationException("Unable to locate ISystemDialogImpl.");
    return service.ShowFileDialogAsync(this, parent);
}

使用方法如下:

这不是最佳写法,后面再附上完整示例代码

private void SelectStationFile()
{
    var dialog = new OpenFileDialog
    {
        Title = "请选择文件"
    };
    var result = dialog.ShowAsync(Views.MainWindow.Instance);
    if (result.Result != null)
    {
        var filePath= result.Result[0];
    }
}

2.跨平台调试的痛

开发环境是Window10、AMD处理器、VisualStudio2022,测试环境是统信UOS、Windows10,CPU均有AMD5000系列和Intel i7系列。
就是打开对话框选择文件这个小小的功能,Windows环境顺畅运行,统信UOS时好时坏,大多数版本都无法正常打开对话框,点击打开对话框的按钮后,应用即进入卡死状态,甚至强制退出都不好使,只能重启电脑。
多次调整代码还是有问题,考虑问题出现的原因可能涉及几方面:

  • UI渲染库:不同的平台使用不同UI渲染库的差异;
  • MVVM模式:MVVM模式默认使用的是ReactiveUI,普通模式则没有限定;
  • UI线程:打开对话框是异步方法,不在主线程内,线程堵塞;

基于上面思路排查问题的过程中,又了解到Avalonia中日志和异常处理的内容。

3.涨知识涨经验

3.1.日志跟踪

Avalonia使用System.Diagnostics.Trace进行日志跟踪,可配置日志跟踪的级别和范围。

public static AppBuilder BuildAvaloniaApp()
    => AppBuilder.Configure<App>()
        .UsePlatformDetect()
        .LogToTrace(LogEventLevel.Debug, LogArea.Property, LogArea.Layout);

也可引用第三方类库将日志输出到控制台或者文件,官方文档中使用的是Serilog

官方文档:Logging Errors and Warnings

3.2.异常处理

在Program.cs的Main方法中可以进行全局异常捕获。

[STAThread]
public static void Main(string[] args)
{
	//日志类库使用Serilog
    Log.Logger=new LoggerConfiguration().WriteTo.File("log.txt",rollingInterval:RollingInterval.Day).CreateLogger();
    try
    {
        BuildAvaloniaApp()
            .StartWithClassicDesktopLifetime(args);
    }
    catch (Exception ex)
    {
        Log.Fatal(ex, "Unhandled Exception");
    }
    finally
    {
        Log.CloseAndFlush();
    }
}
  • 多线程任务相关的异常需要安装TaskScheduler.UnobservedTaskException进行捕获。
  • ReactiveUI相关的异常需要在代码中订阅RxApp.DefaultExceptionHandler进行捕获。

官方文档:Unhandled Exceptions

3.3.访问UI线程

与WPF类似,Avalonia访问主UI线程使用Dispatcher,可以在非UI线程中访问界面对象,位于Avalonia.Threading命名空间下,用法如下:

private void SelectStationFile()
{
     var dialog = new OpenFileDialog
     {
         Title = "请选择文件"
     };
     var result = dialog.ShowAsync(Views.MainWindow.Instance);
     if (result.Result != null)
     {
         Dispatcher.UIThread.Post(() =>
         {
             _stationSourcePath = result.Result[0];
         });
     }
}

官方文档:Accessing the UI thread

4.原因竟是这样

按照前面的思路排查下来竟然还没有解决,百无聊赖之下将绑定命令调用的方法改成async异步,竟然能行了。

这是正确的代码,能够正常工作

private async void SelectClimateFile()
{
    try
    {
        var dialog = new OpenFileDialog
        {
            Title = "请选择文件"
        };
        var result = await dialog.ShowAsync(Views.MainWindow.Instance);
        if (result != null)
        {
            ClimateSourcePath = result[0];
        }

    }
    catch (Exception ex)
    {
        var message = MessageBox.Avalonia.MessageBoxManager.GetMessageBoxStandardWindow("Error", ex.Message);
        message.Show();
    }
}

回想起来,从前后端命令的定义、绑定到基类中打开对话框的实现,都是使用多线程Task,异步的操作应该是必要的。至于为什么使用同步方法时Windows环境能正常工作,Linux环境就不行的原因,还是要更深入的了解底层原理。


只有扎实的基础,才能更快看清问题的本质。

Avalonia是一个**跨平台的UI框架,用于创建桌面应用程序**。 以下是一些关于Avalonia的基本信息和学习资源: 1. **什么是Avalonia?**:Avalonia是一个基于WPF XAML的开源UI框架,它允许开发者使用.NET构建跨平台桌面应用程序。Avalonia支持多种操作系统,包括Windows、Linux和macOS。 2. **准备工作**:在开始使用Avalonia之前,你需要安装相应的开发环境,并配置项目。这通常包括安装.NET SDK和Avalonia工具包。 3. **创建第一个Avalonia应用程序**:你可以通过官方文档或相关教程来创建你的第一个Avalonia应用,这将帮助你理解基本的应用程序结构和开发流程。 4. **XAML基础**:XAML是一种用于定义用户界面的语言,你可以学习如何使用XAML来创建界面布局和实现数据绑定。 5. **控件和样式**:Avalonia提供了丰富的控件库,你可以学习如何使用这些控件以及如何通过样式和模板来自定义它们的外观。 6. **MVVM模式**:MVVM(Model-View-ViewModel)是一种设计模式,用于分离应用程序的业务逻辑和界面表示。学习MVVM将有助于你构建可维护和可测试的应用程序。 7. **导航和多窗口**:了解如何在Avalonia中进行窗口导航和管理多个窗口,这对于构建复杂的桌面应用程序非常重要。 8. **打包和发布应用程序**:最后,你需要学习如何将你的Avalonia应用程序打包和发布,以便用户可以在他们的计算机上安装和使用你的应用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值