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进行赋值

相关推荐
源之缘-OFD先行者27 分钟前
FreeType 介绍及 C# 示例
开发语言·c#
小兵小卒1 小时前
ElectronSharp,.Net跨平台的多一种选择
android·macos·c#·.net·wpf
向宇it2 小时前
【零基础入门unity游戏开发——unity3D篇】URP 3D光源组件(Light)介绍、烘培灯光、实现太阳耀斑镜头光晕效果(基于unity6开发介绍)
开发语言·游戏·3d·unity·c#·游戏引擎
工业甲酰苯胺5 小时前
.NET8.0多线程编码结合异步编码示例
java·算法·.net
刘欣的博客5 小时前
C# 25Dpoint
c#·c# 25dpoint
tonydf5 小时前
浅尝semantic kernel
人工智能·.net
向宇it6 小时前
【零基础入门unity游戏开发——unity3D篇】地形Terrain的使用介绍
开发语言·unity·c#·编辑器·游戏引擎
上位机付工7 小时前
开源免费的上位机数据转换库
开发语言·c#
單細胞生物8 小时前
作業系統恐龍書第十版課後答案 ch04
系统架构