C#界面框架Avalonia中使用依赖注入

Avalonia

  • 定义
    Avalonia 是一个跨平台的.NET 用户界面框架。它允许开发者使用 C# 和 XAML(可扩展应用程序标记语言)来构建桌面、移动和 Web 应用程序。类似于 Windows Presentation Foundation (WPF) 和 Universal Windows Platform (UWP),但具有更广泛的平台兼容性。
  • 平台支持
    它支持 Windows、Linux、macOS 等桌面操作系统,并且通过一些额外的工作和适配,也能够用于移动设备(如 Android 和 iOS,不过在移动方面还在不断完善)和 WebAssembly,实现了真正的跨平台开发。
  • 性能方面
    Avalonia 在性能上有不错的表现。它采用了高效的渲染管道,能够快速地绘制界面元素。例如,在处理复杂的图形界面和大量数据的可视化展示时,它可以有效地利用硬件加速,减少卡顿现象。

Microsoft.Extensions.DependencyInjection

  • 概述
    Microsoft.Extensions.DependencyInjection是.NET 中的一个轻量级的依赖注入 (Dependency Injection,简称 DI)容器框架。它提供了一种在应用程序中管理对象及其依赖关系的方式,是构建可维护、可测试和松散耦合应用程序的关键组件。
    依赖注入是一种设计模式,它允许将对象的创建和其依赖对象的提供从对象本身分离出来。这使得代码更加模块化,更容易进行单元测试和替换实现。

服务生命周期(Service Lifecycle)

  • Transient(临时)
    每次从服务容器中请求一个临时服务时,都会创建一个新的服务实例。这对于无状态的服务或者每次使用都需要独立状态的服务非常有用。例如,一个处理网络请求的服务,每次请求可能都需要一个新的实例来处理不同的数据。
    假设我们有一个DataProcessor服务,它被注册为临时服务。当在不同的地方多次请求这个服务时,每次都会得到一个全新的DataProcessor实例。
  • Scoped(作用域)
    在一个作用域内,同一个服务实例会被共享。作用域通常与请求或者业务操作的范围相关。例如,在一个 Web 请求的上下文中,同一个作用域内的服务实例是相同的。
    以一个 Web API 应用为例,在处理一个 HTTP 请求的过程中,所有在该请求作用域内请求的 Scoped 服务(比如数据库连接服务)会使用同一个实例,当新的请求到来时,会创建新的服务实例。
  • Singleton(单例)
    整个应用程序生命周期内,只有一个服务实例会被创建并共享。这适用于那些需要在整个应用中保持状态一致的服务,比如全局配置服务或者共享资源管理器。
    例如,一个AppSettings服务,用于读取和管理应用程序的配置信息。如果将其注册为单例服务,那么在整个应用运行期间,所有需要访问配置信息的地方都将使用同一个AppSettings实例。

示例

安装依赖注入容器

csharp 复制代码
install-package Microsoft.Extensions.DependencyInjection

注册

在Avalonia的App.xaml的OnFrameworkInitializationCompleted事件中添加容器初始化和构建代码

  • 在 Avalonia 中,OnFrameworkInitializationCompleted是一个重要的生命周期事件。它标志着 Avalonia 框架的初始化过程已经完成,应用程序的主窗口和相关资源已经基本准备就绪。这个事件发生在应用程序启动过程的后期阶段,对于执行一些依赖于框架初始化完成后的操作非常关键。

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

csharp 复制代码
public MainWindow(ISukiToastManager sukiToastManager, ISukiDialogManager sukiDialogManager)

构建部分

csharp 复制代码
ServiceProvider _services;

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();
}

注册部分

csharp 复制代码
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());
}

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<IDistributedCahce, RedisCache>(s =>
    {
        return new RedisCache(s.GetRequiredService<IDatabase>());
    });
}

public static class DialogExManager
{
    static ISukiToastManager ToastManager = new SukiToastManager();

    public static ISukiToastManager GetToastManager() => ToastManager;

    static ISukiDialogManager DialogManager = new SukiDialogManager();

    public static ISukiDialogManager GetDialogManager() => DialogManager;
}

注意: Avalonia如果启用了ViewLocator,那么ViewModel和View将会自动绑定,如下

csharp 复制代码
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);

        if (type != null)
        {
            return (Control)Activator.CreateInstance(type)!;
        }

        return new TextBlock { Text = "Not Found: " + name };
    }

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

若未启用ViewLocator,则自行在打开或复制Window的时候,对DataContext进行赋值

相关推荐
csdn_aspnet8 小时前
C# 在逗号分割的字符串中判断是否包含指定字符
c#·正则·linq·string·regex·contains
宝桥南山8 小时前
Blazor Web Assembly - 体验一下Authentication State从Server共享给Client
microsoft·微软·c#·asp.net·.net·.netcore
淡海水10 小时前
02-06-历史-托管GC机制-垃圾回收如何影响数据结构选择
c#·编译·gc·机器码
Chris _data13 小时前
WPF 上位机开发学习笔记 - 第四天
笔记·学习·wpf
一几文13 小时前
2026年上半年软考高级-系统架构设计师考试真题回顾与解析-综合知识选择题6
小程序·架构·系统架构·软考高级·软考·it证书
海水冷却16 小时前
私有化 vs 混合云 vs 公有云:双录系统架构怎么选
系统架构·双录
Cicada12817 小时前
为什么从 demo 到生产路还很长?一次数据拉取功能的复杂度演进复盘
系统架构
longxiaozhang620 小时前
C# static:静态成员,小白也能看懂
开发语言·c#
longxiaozhang620 小时前
C#继承:让代码少写一点,偷懒的好方法
开发语言·c#
xcl092521 小时前
树洞社交应用的系统架构设计与匿名实现
java·spring boot·系统架构