Featured image of post Avalonia中使用依赖注入重构代码

Avalonia中使用依赖注入重构代码

Avalonia框架结合Microsoft.Extensions.DependencyInjection实现跨平台UI开发,通过服务注册、生命周期管理和视图定位器机制,显著提升代码解耦度和可维护性。

🧩 Avalonia 框架概览

🔍 简介

Avalonia 是一个 跨平台的 .NET 用户界面框架,支持使用 C# 和 XAML 构建桌面、移动和 Web 应用程序。其设计灵感来源于 WPF 和 UWP,但具有更强的跨平台兼容性。

✅ 主要特点:

  • 使用熟悉的 XAML 语法
  • 支持多种 UI 控件和样式
  • 可运行于多个操作系统
  • 支持 MVVM 模式及依赖注入

🌐 平台支持

Avalonia 支持以下平台:

平台 支持情况
Windows 完全支持
Linux 完全支持
macOS 完全支持
Android/iOS 实验性支持(需额外适配)
WebAssembly 支持(通过 WASM 渲染器)

💡 Avalonia 提供了真正的跨平台开发能力,适用于需要统一多端体验的应用场景。


⚙️ 性能表现

Avalonia 的渲染引擎经过优化,具备高效的绘制能力和良好的硬件加速支持,尤其在处理复杂图形与数据可视化时表现出色。

  • 高效的渲染管道
  • 支持 GPU 加速
  • 低延迟响应用户交互

例如:当应用中存在大量动态图表或动画元素时,Avalonia 能保持流畅的帧率,避免卡顿现象。


🔄 Microsoft.Extensions.DependencyInjection 详解

📦 概述

Microsoft.Extensions.DependencyInjection 是 .NET 中的一个 轻量级依赖注入(DI)容器,它提供了一种灵活的方式来管理应用程序中的对象及其依赖关系。

💡 为什么使用 DI?

  • 解耦业务逻辑与具体实现
  • 提高代码可测试性和可维护性
  • 支持模块化开发

🕒 服务生命周期(Service Lifecycle)

生命周期类型 描述
Transient(瞬态) 每次请求都会创建新实例,适合无状态服务
Scoped(作用域) 同一作用域内共享同一个实例,常用于 Web 请求上下文
Singleton(单例) 整个应用程序周期内共享唯一实例,适合全局资源管理

示例说明:

  • Transient:每次调用 IDataProcessor 都会返回一个新的实例。
  • Scoped:在一次 HTTP 请求中,所有对 IDatabaseContext 的请求都返回同一个实例。
  • Singleton:如 IAppSettings,在整个应用程序中始终为同一实例。

🧪 示例:在 Avalonia 中集成依赖注入

📝以下示例将添加Redis和第三方Avalonia样式库SukiUI作为参考

1️⃣ 安装依赖注入包

1
install-package Microsoft.Extensions.DependencyInjection

2️⃣ 初始化服务容器

App.xaml.cs 中重写 OnFrameworkInitializationCompleted() 方法以注册并构建服务容器。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public override void OnFrameworkInitializationCompleted()
{
    var collection = new ServiceCollection();
    collection.AddCommonServices();
    collection.AddDistributedCache();

    _services = collection.BuildServiceProvider();

    var vm = _services.GetRequiredService<MainWindowViewModel>();
    var toastService = _services.GetRequiredService<ISukiToastManager>();
    var dialogService = _services.GetRequiredService<ISukiDialogManager>();

    if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
    {
        desktop.MainWindow = _services.GetRequiredService<MainWindow>();
    }
    else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewPlatform)
    {
        singleViewPlatform.MainView = new MainWindow(toastService, dialogService)
        {
            DataContext = vm,
        };
    }

    base.OnFrameworkInitializationCompleted();
}

3️⃣ 注册服务

自定义扩展方法注册常用服务

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public static void AddCommonServices(this IServiceCollection collection)
{
    collection.AddSingleton<MainWindowViewModel>();
    collection.AddSingleton<MainWindow>(s => new MainWindow(
        s.GetRequiredService<ISukiToastManager>(),
        s.GetRequiredService<ISukiDialogManager>()
    )
    {
        DataContext = s.GetRequiredService<MainWindowViewModel>(),
    });

    collection.AddSingleton<ISukiToastManager>(s => DialogExManager.GetToastManager());
    collection.AddSingleton<ISukiDialogManager>(s => DialogExManager.GetDialogManager());
}

注册 Redis 缓存服务

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public static void AddDistributedCache(this IServiceCollection collection)
{
    var connection = ConnectionMultiplexer.Connect("127.0.0.1:6379");
    var redis = connection.GetDatabase();

    collection.AddSingleton(redis);
    collection.AddSingleton(connection);
    collection.AddSingleton<IDistributedCache, RedisCache>(s =>
    {
        return new RedisCache(s.GetRequiredService<IDatabase>());
    });
}

4️⃣ 辅助类:对话框与 Toast 管理器

1
2
3
4
5
6
7
8
public static class DialogExManager
{
    private static readonly ISukiToastManager ToastManager = new SukiToastManager();
    private static readonly ISukiDialogManager DialogManager = new SukiDialogManager();

    public static ISukiToastManager GetToastManager() => ToastManager;
    public static ISukiDialogManager GetDialogManager() => DialogManager;
}

5️⃣ 视图定位器(ViewLocator)

如果启用了 ViewLocator,则 ViewModel 与 View 将自动绑定。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
public class ViewLocator : IDataTemplate
{
    public Control? Build(object? param)
    {
        if (param is null) return null;

        var name = param.GetType().FullName!.Replace("ViewModel", "View", StringComparison.Ordinal);
        var type = Type.GetType(name);

        return type != null ? (Control)Activator.CreateInstance(type)! : new TextBlock { Text = "Not Found: " + name };
    }

    public bool Match(object? data)
    {
        return data is ViewModelBase;
    }
}

📝 如果未启用 ViewLocator,则需要手动设置 DataContext


✅ 总结

Avalonia 是一个强大的跨平台 UI 框架,结合 Microsoft.Extensions.DependencyInjection 可实现高度解耦和模块化的应用程序架构。通过合理配置服务生命周期和使用视图定位器等机制,可以显著提升开发效率和代码质量。


Built with Hugo
Theme Stack designed by Jimmy