前言

使用依赖注入可以让我们的程序变得更加好维护与测试。

今天分享的是在Avalonia/C#中使用依赖注入。

我准备了一个简单的不使用依赖注入与使用依赖注入的demo。

该demo已上传至GitHub,地址:https://github.com/Ming-jiayou/Avalonia_With_Dependency_Injection_Example

因此本文中不会包含全部代码,有需要可以从GitHub获取全部代码。

实践

先运行一下AvaloniaWithoutDependencyInjection这个例子。

效果:

虽然我们实现了导航的功能,但是当重新点击的时候又会创建一个新的实例,并不会保留之前的状态,很多时候这不是我们想要的效果。

现在再来运行一下AvaloniaWithDependencyInjection这个例子。

效果:

由于我们以单例的形式将View与ViewModel注入了依赖注入容器中了,因此你可以看到现在再重新点击是会保留之前的状态了。

现在让我们一起看看如何将上面的那个例子改造成下面的那个例子吧!!

要实现依赖注入首先需要有一个依赖注入容器,我这里使用的是Microsoft.Extensions.DependencyInjection。

为了方便实现导航,我们创建一个INavigationService接口与NavigationService类。

INavigationService:

public interface INavigationService
{
ViewModelBase CurrentViewModel { get; }
void NavigateTo<T>() where T : ViewModelBase;
}

NavigationService:

public partial class NavigationService : ObservableObject, INavigationService
{
[ObservableProperty]
private ViewModelBase _currentViewModel; private readonly IServiceProvider _serviceProvider; public NavigationService(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider; // 设置初始页面
NavigateTo<Page1ViewModel>();
} public void NavigateTo<T>() where T : ViewModelBase
{
var viewModel = _serviceProvider.GetRequiredService<T>();
CurrentViewModel = viewModel;
}
}

为了方便添加服务,创建一个ServiceCollectionExtensions类。

public static class ServiceCollectionExtensions
{
public static IServiceCollection AddViews(this IServiceCollection services)
{
// Register all views as singletons
services.AddSingleton<MainWindow>();
services.AddSingleton<Page1View>();
services.AddSingleton<Page2View>(); return services;
} public static IServiceCollection AddViewModels(this IServiceCollection services)
{
// Register all view models as singletons
services.AddSingleton<MainWindowViewModel>();
services.AddSingleton<Page1ViewModel>();
services.AddSingleton<Page2ViewModel>(); return services;
} public static IServiceCollection AddServices(this IServiceCollection services)
{
services.AddSingleton<INavigationService, NavigationService>();
return services;
}
}

在Program中注册服务:

在App.axaml.cs中从容器中取出MainWindow与MainWindowViewModel:

在ViewLocator中从容器中取出View的实例:

MainWindowViewModel:

经过以上步骤就成功在Avalonia中实现依赖注入了,现在来看看流程是怎么样的。

流程

程序启动在Program中注册了服务。

App.axaml.cs中取出了MainWindow与MainWindowViewModel。

在MainWindowViewModel中注入了INavigationService。

但是在这里你可能会有疑问:

为什么这里可以直接使用serviceProvider呢?

看起来我们直接使用了 serviceProvider,但实际上这里涉及到了依赖注入容器的生命周期和服务解析顺序。

当我们调用 services.BuildServiceProvider() 时,依赖注入容器会:

  • 创建一个服务提供者(ServiceProvider)实例

  • 这个 ServiceProvider 包含了所有注册的服务的信息和创建规则

当需要 NavigationService 时,依赖注入容器会:

  • 发现需要创建 NavigationService
  • 看到 NavigationService 的构造函数需要一个 IServiceProvider
  • 将自己(serviceProvider)作为参数传入
  • 创建 NavigationService 实例

在某处第一次请求INavigationService时发生的:

var navigationService = serviceProvider.GetService<INavigationService>();

此时:

  • serviceProvider 已经是完全初始化好的实例

  • 所有的 ViewModel 都已经注册完成

  • 当调用 NavigateTo<Page1ViewModel>() 时,可以成功从容器中解析出 Page1ViewModel

然后初始导航到Page1ViewModel。

从容器中取出Page1ViewModel并赋值给CurrentViewModel。

当CurrentViewModel改变的时候,会触发MainWindowViewModel订阅的这个属性变更事件:

如果是CurrentViewModel属性发生变化,就将MainWindowViewModel中的CurrentPage属性赋值为CurrentViewModel。

CurrentPage类型为ViewModelBase,它的变化会触发ViewLocator中的Build方法:

该方法会根据CurrentPage的类型从容器中取出对应的View,从而实现了导航的功能,并且能够保留之前的状态。

最后

以上就是在Avalonia/C#中使用依赖注入的过程,希望对你有所帮助。

在Avalonia/C#中使用依赖注入过程记录的更多相关文章

  1. 在WPF中使用依赖注入的方式创建视图

    在WPF中使用依赖注入的方式创建视图 0x00 问题的产生 互联网时代桌面开发真是越来越少了,很多应用都转到了浏览器端和移动智能终端,相应的软件开发上的新技术应用到桌面开发的文章也很少.我之前主要做W ...

  2. ASP.NET Core中的依赖注入(1):控制反转(IoC)

    ASP.NET Core在启动以及后续针对每个请求的处理过程中的各个环节都需要相应的组件提供相应的服务,为了方便对这些组件进行定制,ASP.NET通过定义接口的方式对它们进行了"标准化&qu ...

  3. ASP.NET Core中的依赖注入(2):依赖注入(DI)

    IoC主要体现了这样一种设计思想:通过将一组通用流程的控制从应用转移到框架之中以实现对流程的复用,同时采用"好莱坞原则"是应用程序以被动的方式实现对流程的定制.我们可以采用若干设计 ...

  4. ASP.NET Core中的依赖注入(4): 构造函数的选择与服务生命周期管理

    ServiceProvider最终提供的服务实例都是根据对应的ServiceDescriptor创建的,对于一个具体的ServiceDescriptor对象来说,如果它的ImplementationI ...

  5. NET Core 中的依赖注入

    NET Core 中的依赖注入 [共7篇] 一.控制反转(IoC) ASP.NET Core在启动以及后续针对每个请求的处理过程中的各个环节都需要相应的组件提供相应的服务,为了方便对这些组件进行定制, ...

  6. .NET CORE——Console中使用依赖注入

    我们都知道,在 ASP.NET CORE 中通过依赖注入的方式来使用服务十分的简单,而在 Console 中,其实也只是稍微绕了个小弯子而已.不管是内置 DI 组件或者第三方的 DI 组件(如Auto ...

  7. Asp.net core中的依赖注入

    使用服务 在Asp.net core的Controller中,可以通过如下两种方式获取系统注入的服务: 构造函数 可以直接在构造函数中传入所依赖的服务,这是非常常见的DI注入方式. public Va ...

  8. 深入理解net core中的依赖注入、Singleton、Scoped、Transient(四)

    相关文章: 深入理解net core中的依赖注入.Singleton.Scoped.Transient(一) 深入理解net core中的依赖注入.Singleton.Scoped.Transient ...

  9. 深入理解net core中的依赖注入、Singleton、Scoped、Transient(三)

    相关文章: 深入理解net core中的依赖注入.Singleton.Scoped.Transient(一) 深入理解net core中的依赖注入.Singleton.Scoped.Transient ...

  10. 深入理解net core中的依赖注入、Singleton、Scoped、Transient(二)

    相关文章: 深入理解net core中的依赖注入.Singleton.Scoped.Transient(一) 深入理解net core中的依赖注入.Singleton.Scoped.Transient ...

随机推荐

  1. RoboMaster- RDK X5能量机关实现案例(一)识别

    作者:SkyXZ CSDN:https://blog.csdn.net/xiongqi123123 博客园:https://www.cnblogs.com/SkyXZ 在RoboMaster的25赛季 ...

  2. 什么是Lambda架构?

    一.简介 Lambda架构(Lambda Architecture)是由Twitter工程师南森·马茨(Nathan Marz)提出的大数据处理架构. 这一架构的提出基于马茨在BackType和Twi ...

  3. Luogu P11361 NOIP2024 编辑字符串 题解 [ 黄 ] [ 贪心 ]

    编辑字符串:这题能评蓝已经说明了洛谷的唐氏. 结论 找到两个字符串种连续的且可以移动的所有极大子区间,然后线性扫一遍,看这一位所处的子区间中有多少个 \(0\) 和 \(1\),两个都有 \(0\) ...

  4. 乌龟冬眠箱湿度监控系统和AI辅助建议功能的实现

    家里小朋友养了一只小乌龟,到了冬天就冬眠了,早早地准备了一个冬眠箱,铺上椰土,在室温低于15℃时,就把小乌龟放到冬眠箱里,不一会儿它就自己钻入土中把自己藏了起来.按照惯例,需要每隔一定时间,对冬眠箱进 ...

  5. 职场软素质&算法工程师的硬素质--卓越的职场人需要的42种能力

    经过自己在实际的工作中摸爬滚打,个人觉得一些方面的能力是非常重要的,可以让自己在职场中快速的脱颖而出,因此,从硬实力,软实力两个方面进行总结如下: 软实力: (1)解决问题的能力 (2)预估风险的能力 ...

  6. Python - [04] 面试题汇总

    题记部分 001 || Python的特点和优点 Python可以作为编程的入门语言,因为他具有以下特质: (1)解释型 (2)动态特性 (3)面向对象 (4)语法简洁 (5)开源 (6)丰富的社区资 ...

  7. JAVA实现AES加密、解密

    一.什么是AES? 高级加密标准(英语:Advanced Encryption Standard,缩写:AES),是一种区块加密标准.这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用. ...

  8. java如何实现对List集合进行分页

    对List集合进行分页: private <T> Page<T> listToPage(List<T> dataList, Integer pageSize, In ...

  9. rust学习笔记(6)

    模块 定义自己的模块,方便外部的调用 mod可以嵌套 可见程度 分为private和public 其中pub可以分为模块内可见和模块外可见 mod也遵循可见性的要求 // 一个名为 `my_mod` ...

  10. 事务及mysql中的隔离级别

    事务,一个或一组sql语句组成的执行单元,是最小的执行单元,要么全执行,要么全不执行.如果单元中某条sql语句执行失败,整个单元将会回滚,所有受影响的数据返回到事务开始前的状态. 事务具有ACID四个 ...