CommunityToolkit.Mvvm笔记---Ioc

使用MVVM模式提高应用程序代码库中的模块化程度的最常用模式是使用某种形式的反转控制(Ioc)。其中最常见的解决方案是使用依赖关系注入,该解决方案存在于创建多个注入后端类的服务(即以参数的形式传递给 viewmodel 构造函数)的过程中,这允许使用这些服务的代码不依赖这些服务的实现详细信息,并且也可以轻松地交换这些服务的具体实现。 这种模式还可以通过服务将特定于平台的功能抽象出来,然后在需要的地方注入这些功能,从而使后端代码可以轻松使用这些功能。

MVVM工具包没提供内置的API来促进这种模式的使用,因为已经有专用库(Microsoft.Extensions.DependencyInjection 包),本文中示例都是参考此库。

什么是依赖注入

依赖注入又称为依赖项注入,那什么是依赖项呢?比如在一个类A中,实现某中功能,而此功能是另外一个类B实现的,那就说明A依赖B,B就是A的依赖项。或者是另一个对象A所依赖的对象B。

public class MyDependency
{public void WriteMessage(string message){Console.WriteLine($"MyDependency.WriteMessage called. Message: {message}");}
}

类可以创建 MyDependency 类的实例,以便利用其 WriteMessage 方法。 在以下示例中,MyDependency 类是 IndexModel 类的依赖项 

public class IndexModel : PageModel
{private readonly MyDependency _dependency = new MyDependency();public void OnGet(){_dependency.WriteMessage("IndexModel.OnGet");}
}

注意:在上述示例中,MyDependency 类依赖于IndexModel 类,所以IndexModel 就是MyDependency 的依赖项。 硬编码的依赖项(如前面的示例)会产生问题,应避免使用。

强依赖关系具有以下几个问题:

  • 如果要用不同的实现替换 MyDependency ,必须修改 IndexModel 类。
  • 如果 MyDependency 具有依赖项,则必须由 IndexModel 类对其进行配置,且很难进行初始化。
  • 这种实现很难进行单元测试。

那如何解决上述依赖关系所造成的弊端呢?答案就是依赖项注入。可通过如下几个步骤实现:

  • 使用接口或基类将依赖关系实现抽象化。
  • 在服务容器中注册依赖关系。
  • 将服务注入到使用它的类的构造函数中。

 .NET 提供了一个内置的服务容器 IServiceProvider。 服务通常在应用启动时注册,并追加到 IServiceCollection。 添加所有服务后,可以使用 BuildServiceProvider 创建服务容器。 框架负责创建依赖关系的实例,并在不再需要时将其释放。

简单一句话说:依赖注入(DI)将所依赖的对象参数化,接口化,并且将依赖对象的创建和释放剥离出来,这样就做到了解耦,并且实现了控制反转(IoC)

控制反转(IoC)具有如下两个特点:

  • 高等级的代码不能依赖低等级的代码;
  • 抽象接口不能依赖具体实现;

控制反转解决代码的强耦合,增加了代码的可扩展性。依赖注入将依赖具体实现类和控制实现类的创建和释放,变成了依赖接口或抽象类,不再控制接口的创建和释放。两者之间相辅相成,互相成就。

WPF依赖注入示例

步骤 1: 设置项目和安装必要的NuGet包

Install-Package Microsoft.Extensions.DependencyInjection

 或者

步骤 2: 创建依赖注入容器

创建一个静态类来构建和存储IServiceProvider实例。这个类将负责配置服务和解析依赖。

创建 DependencyInjection.cs
using Microsoft.Extensions.DependencyInjection;
using System;public static class DependencyInjection
{private static IServiceProvider serviceProvider;public static void ConfigureServices(){var services = new ServiceCollection();// 注册应用中的服务和ViewModelservices.AddSingleton<MainWindow>();services.AddTransient<IMyService, MyService>();services.AddTransient<MainViewModel>();serviceProvider = services.BuildServiceProvider();}public static T GetService<T>(){return serviceProvider.GetService<T>();}
}

在这个类中,我们使用了Microsoft.Extensions.DependencyInjection来创建服务集合,然后构建IServiceProvider

步骤 3: 配置主窗口和ViewModel

修改你的MainWindow,使其可以接收依赖(比如MainViewModel

MainWindow.xaml.cs
public partial class MainWindow : Window
{public MainWindow(MainViewModel viewModel){InitializeComponent();DataContext = viewModel;}
}

步骤 4: 配置 App.xaml.cs

重写App.xaml.cs中的启动逻辑,使用依赖注入初始化MainWindow

App.xaml.cs
using System.Windows;public partial class App : Application
{protected override void OnStartup(StartupEventArgs e){base.OnStartup(e);DependencyInjection.ConfigureServices();var mainWindow = DependencyInjection.GetService<MainWindow>();mainWindow.Show();}
}

这里,应用启动时会配置服务,并从服务提供者中获取MainWindow的实例。

注意:在此示例中,MainWindow通过服务注册的方式进行实例化,所以需要删除默认的App.xaml中StartUri属性设置,否则将提示默认构造函数不存在。

步骤 5: 创建服务和ViewModel

定义服务接口和实现,以及ViewModel。

IService 和 Service 实现
public interface IMyService
{string GetData();
}public class MyService : IMyService
{public string GetData(){return "Hello from MyService!";}
}

 ViewModel 实现

public class MainViewModel
{public string Data { get; }public MainViewModel(IMyService myService){Data = myService.GetData();}
}

步骤 6: xaml视图

<Grid><TextBlock Text="{Binding Data}"></TextBlock><Frame x:Name="MainFrame" Source="Views/Pages/RegistrationForm.xaml"  NavigationUIVisibility="Hidden" ></Frame>
</Grid>

经过上述步骤,就实现了WPF中依赖注入和控制反转,测试结果如下:

 题外话:生命周期和存储方式小知识

在WPF应用程序中,通过依赖注入(DI)获取的对象(例如,通过重写OnStartup方法并从IServiceProvider获取的实例)通常不会“自动消失”或自动释放,除非你的实现或应用程序逻辑中有特定的处理使其被释放或被垃圾回收。

生命周期和存储方式

对象的持久性和存储方式主要取决于如何在依赖注入容器中注册这些对象:

  1. 单例(Singleton):只创建一个实例,该实例在应用程序的整个生命周期内持续存在。例如,注册为单例的MainWindow,在应用程序关闭前,其实例会一直存在。

  2. 瞬态(Transient):每次请求都创建一个新的实例。这意味着每次从IServiceProvider获取时都会创建一个新的对象。

  3. 作用域(Scoped):在.NET Core的Web应用中常用,每个请求创建一个新的实例,但在WPF中通常使用单例或瞬态替代。

在上述示例中,MainWindow如果注册为单例,则在应用程序关闭之前始终存在。如果注册为瞬态,那么每次调用GetService<MainWindow>()时都会创建一个新的MainWindow实例。

生命周期管理

  • 引用保持:为了确保通过依赖注入获取的对象不会“消失”,你需要保持对这些对象的引用。在WPF中,通常的做法是保持对主窗口或核心服务的引用直到应用程序关闭。
  • 释放资源:对于使用了资源较多的服务或对象,如数据库连接或文件句柄,应确保适当地管理其生命周期。这可能需要实现IDisposable接口,并在适当的时候(如窗口关闭或对象不再需要时)调用Dispose方法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/818302.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ELK+Filebeat日志分析系统

一、ELK基本介绍&#xff1a; 1.ELK 简介: ELK平台是一套完整的日志集中处理解决方案(日志系统)。 将 ElasticSearch、Logstash 和 Kiabana 三个开源工具配合使用&#xff0c; 完成更强大的用户对日志的查询、排序、统计需求。 ELK --> ELFK --> ELFKMQ2.ELK组件介绍…

IDEA创建jsp文件具体步骤

1. 创建普通项目 2.文件->项目结构->模块&#xff0c;点击号&#xff0c;选择web 点击确认 3.配置工件 4.配置tomcat 点击确定 5.创建jsp文件&#xff0c;注意创建位置 6.然后换调试位置 注意此时不能有其他的web项目运行,否则就选不了路径 完成后运行即可

Python代码打包成exe程序

国内镜像源 清华大学 https://pypi.tuna.tsinghua.edu.cn/simple阿里云 https://mirrors.aliyun.com/pypi/simple/豆瓣 https://pypi.douban.com/simple/ 百度云 https://mirror.baidu.com/pypi/simple/中科大 https://pypi.mirrors.ustc.edu.cn/simple/华为云 https://mirror…

Pytorch - 张量转换拼接

目录 张量转换为 numpy 数组 numpy 转换为张量 标量张量和数字的转换 张量拼接操作 张量索引操作 &#x1f606;&#x1f606;&#x1f606;感谢大家的观看&#x1f606;&#x1f606;&#x1f606; 张量转换为 numpy 数组 &#x1f50e;使用 Tensor.numpy 函数可以将张量…

Gradle JDK 和项目JDK的区别

compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget “1.8” } 在Android项目中&#xff0c;compileOptions和kotlinOptions的配置与Gradle所使用的JDK版本没有直接冲突。这些选项是用…

MySQL 使用C语言

一般使用MySQL很少用命令行&#xff0c;一般都是通过程序内部使用&#xff0c;MySQL也为不同的语言定制了不同的头文件和库函数&#xff0c;可以在自己的程序中通过包含头文件和编译时候链接库函数来使用MySQL。 现在一般安装MySQL的时候就会自动给你安装库函数和头文件。 可…

数据资产管理制度探索——浙江篇

在行政事业单位数据资产管理领域&#xff0c;浙江省以创新性思维与高质量发展的战略眼光&#xff0c;积极探索并构建了具有前瞻性和实效性的数据资产管理制度。作为财政部数据资产管理试点省份&#xff0c;浙江省财政厅与省标准化研究院强强联合&#xff0c;充分运用数据溯源、…

【报错】TypeError: Cannot read property ‘meta‘ of undefined

&#x1f608;解决思路 首先这里很明显我们能看到是缺少该参数&#xff1a;meta。 但是经过查找后发现和该参数无关。 &#x1f608;解决方法 后来我上网搜了下&#xff0c;网上的回答大部分偏向于是package.json这个文件中的tabBar.list数组对象只有一条的问题。 网上的大…

基于SpringBoot + Vue实现的租房管理系统设计与实现+毕业论文+开题报告​(包运行成功)

介绍 管理员的主要功能设计为&#xff1a;密码信息管理、注册用户管理、区域管理、出租管理等模块。 房主的主要功能设计为&#xff1a;密码信息管理、个人信息管理、订单管理等模块。 用户的主要功能设计为&#xff1a;用户登录、密码管理、出租管理、收藏管理等模块。 源码论…

数据结构---线性表

1&#xff0c;顺序表实现---动态分配 #include<stdlib.h> #define InitSize 10 typedef struct {int *data;//静态分配int length;int MaxSize; }SqList; void InitList(SqList& L) {L.data (int*)malloc(InitSize * sizeof(int));//分配空间L.length 0;L.MaxSize…

编译 dtbocfg 模块是遇到的问题

编译 dtbocfg 模块 报错1 在编译 dtbocfg.c CC [M] /home/book/imx6ull/kernal_modul/00_dtbocfg/dtbocfg.o /home/book/imx6ull/kernal_modul/00_dtbocfg/dtbocfg.c:253:1: warning: data definition has no type or storage classCONFIGFS_ATTR(dtbocfg_overlay_item_, dt…

【测试开发学习历程】python常用的模块(上)

前言&#xff1a; 感觉全是机器人给我点赞和收藏&#xff08;QWQ&#xff09;&#xff0c;能不能来个活人评论我啊&#xff0c;行行好&#xff08;QAQ&#xff09; 目录 1 模块的导入 2 随机模块-random 3 字符串模块-string 4 os模块及其常用函数 1 模块的导入 库、包、…

关于SpringCloud,你了解多少?

Why SpringCloud&#xff1f; Spring cloud 是一系列框架的有序集合。它利用 spring boot 的开发便利性巧妙地简化了分布式系统基础设施的开发&#xff0c;如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等&#xff0c;都可以用 spring boot 的开发风格做到一…

C++ 标准库中的 <algorithm> 头文件

C 标准库中的 <algorithm> 头文件包含了一系列非常有用的算法函数&#xff0c;这些函数可以用于处理容器&#xff08;如向量、列表、数组等&#xff09;中的元素。这些算法可以极大地简化编程任务&#xff0c;使代码更加简洁和易于理解。 以下是一些 <algorithm> …

论坛直击|发展新质生产力,高校怎么做?

新质生产力浪潮涌动 三大议题聚焦高校人才培养 今年全国两会的政府工作报告将“大力推进现代化产业体系建设&#xff0c;加快发展新质生产力”列在2024年政府工作任务首位&#xff0c;发展新质生产力的先导是培养拔尖创新人才&#xff0c;高等教育改革必须以立德树人为根本任…

带你从BIOS 小工到年薪百万 之 sense amplifier 的作用以及MRC 如何初始化它

做过BIOS 的同学&#xff0c;肯定看过这张图片 对世界充满好奇心的你&#xff0c;是否想过 其中 Sense amplifier 是做什么用的&#xff1f; 是如何工作的&#xff1f; BIOS 又是如何训练它的&#xff1f; 明天接着写

[C++11] 初始化语法、explicit关键字、final override关键字、delete default关键字

说明&#xff1a;C11 引入了初始化语法、explicit关键字、final && override关键字、delete && default关键字 等新特性&#xff0c;旨在改善语言的功能性、安全性和表达能力。具体说明如下&#xff1a; 引入初始化列表和统一的初始化语法的原因&#xff1a;在…

分布式的计算框架之Spark(python第三方库视角学习PySpark)

基本介绍 Apache Spark是专为大规模数据处理而设计的快速通用的计算引擎 。现在形成一个高速发展应用广泛的生态系统。 特点介绍 Spark 主要有三个特点&#xff1a; 首先&#xff0c;高级 API 剥离了对集群本身的关注&#xff0c;Spark 应用开发者可以专注于应用所要做的计…

transformer在生物基因DNA的应用:DNABERT、DNABERT-2

参考&#xff1a; https://www.youtube.com/watch?vmk-Se29QPBA&t1388s 写明这些训练模型可以最终训练好可以进行DNA特征向量的提取&#xff0c;应用与后续1、DNABERT https://github.com/jerryji1993/DNABERT 主要思路就是把DNA序列当成连续文本数据&#xff0c;直接用…

维修伊顿触摸屏不显示工业电脑人机界面EATON XVS-430-10MPI-1-10 深圳捷达工控维修

人机界面 (HMI) XP500 工业 PC 系列 以不同的方式思考工业平板电脑 对于严酷、高要求的应用&#xff0c;工业平板电脑设定了可配置性和稳健性的标准。伊顿的 XP500 系列工业平板电脑凭借防刮钢化玻璃屏幕、铸铝外壳和无风扇设计满足了这些需求。这些功能使 XP500 HMI成为一款节…