文章目录
- 专栏和Gitee仓库
- 前言
- IOC容器
- Prism IOC使用
- 声明两个测试的服务类
- MainWindow IOC 注入[单例]
- MainWindow里面获取
- UserController无法使用
- 官方解决方案
- 使用自定义IOC容器,完美解决
- 既然Prism不好用,直接上微软的IOC
- 解决方案
- App.xaml.cs
- ViewModel里面直接调用
- 运行结果
- 总结
专栏和Gitee仓库
WPF仿网易云 Gitee仓库
WPF仿网易云 CSDN博客专栏
前言
上一篇文章中,我们简单讲解了一下父子通讯的逻辑。父子通讯是强绑定逻辑。这里我们将讲解消息订阅通讯的方式。消息订阅一般用于[页]和[页]之间通讯。
IOC容器
IOC容器有许多容器,目前.NET 有两个最优的依赖注入框架
- Microsoft.Extensions.DependencyInjection:微软官方依赖注入框架,听说在.net core 8.0得到了最强的性能提升
- Autofac:听说也是最强的依赖注入框架,性能强,开销低,功能完善。
Dependency injection in ASP.NET Core
Autofac 官网
深入浅出依赖注入容器——Autofac
.NET Core 依赖注入 Microsoft.Extensions.DependencyInjection
当然,Prism也有自己的IOC容器。
WPF Prims框架详解
我们这里使用Prism的IOC容器。因为Prism提供了全套的解决方案
Prism IOC使用
我之前使用过微软的IOC,这里我就不展开说明了。IOC容器的使用都是大差不多的。
Prism.Unity 依赖注入(IOC)的使用
声明两个测试的服务类
namespace BlankApp1.Services{public class TestA_Service{public string Name { get; set; }public TestA_Service() {Name = "小王";}}}
namespace BlankApp1.Services{public class TestB_Service{public TestA_Service TestA_Serivce { get; set; }public string Name { get; set; }public TestB_Service(TestA_Service testA_Serivce){TestA_Serivce = testA_Serivce;Name = "小红";}}}
MainWindow IOC 注入[单例]
我们目前所有注入的IOC容器实例都是单例注入,生命周期暂时不考虑。
在App.xaml里面注入IOC容器
/// /// 这里是IOC容器的注入端口/// /// protected override void RegisterTypes(IContainerRegistry containerRegistry){//这里对TestA_Service进行修改,查看IOC容器是否为单例。containerRegistry.RegisterSingleton<TestA_Service>(sp =>{return new TestA_Service(){Name = "小丽",};});containerRegistry.RegisterSingleton<TestB_Service>();//注入MainWindow,这里注入先后没有影响containerRegistry.RegisterSingleton<MainWindow>();}
MainWindow里面获取
public MainWindow(TestB_Service testB_Service){InitializeComponent();ViewModel = (MainWindowViewModel)DataContext;ViewModel.MainWindow = this;ViewModel.TestB_Service = testB_Service;}
结果:获取成功!
UserController无法使用
但是如果我们使用TitleView会怎么样?
原因是为什么?因为是因为我们使用的是父子组件构造,但是这样WPF默认使用的是New 一个新对象,是无参构造。所以会报这个错误。
官方解决方案
Composing the User Interface Using the Prism Library for WPF
官方的解决比较简单粗暴,官方认为所有的UserController都是Prism构造的,这里面使用的是Prism的Region方案。所有的信息流都是通过Messager去设置的,如果是这样设置的话,我们所有的父子通讯都失败了。而且由于Messager的单一化,导致我们无法复用组件,因为如果存在多个组件ViewA,你不能确认ViewA到底是哪个ViewA,这个和我们的单例注入相违背。
使用自定义IOC容器,完美解决
Prism最大的问题,就是他是侵入式框架,你必须按照Prism的解决方案才能解决问题。而且给的方案都比较死。
既然Prism不好用,直接上微软的IOC
为什么要用微软的IOC容器,一个是微软的好用,另一个是ASP.NET Core也都是微软的IOC。能用一个解决就不学新的。
.NET Core 依赖注入 Microsoft.Extensions.DependencyInjection
解决方案
App.xaml.cs
/// /// 全局静态IOC构造器/// public readonly static ServiceProvider ServiceProvider;/// /// 静态构造,这里以单例举例/// static App() {IServiceCollection services = new ServiceCollection();services.AddSingleton<TestB_Service>();services.AddSingleton<TestA_Service>(sp =>{return new TestA_Service(){//测试是否被修改。默认小王,修改为小兰Name = "小兰"};});ServiceProvider = services.BuildServiceProvider();var res = ServiceProvider.GetService<MainWindowViewModel>();}
ViewModel里面直接调用
public MainWindowViewModel(){//直接从构造器里面拿到单例TestB_Service = App.ServiceProvider.GetService<TestB_Service>();}
运行结果
其实通过Service可以进行间接通讯。这里我就不展开说明了。
总结
因为父子组件开发的特点,所有的UserController都可能存在多个,所以UserController是不能进行IOC的。因为IOC会有两个源,一个是Xaml实例化,另一个是IOC容器。还有一个问题是Xaml语法是不能进行IOC的,而且由于生命周期的原因,IOC实例化之前会报错。所以直接放弃UserController的IOC注入。
但是Services服务类可以进行IOC注入,比如数据库操作,网络通讯,业务逻辑(比如用户登录)。
我们目前已经完美解决了WPF 的信息流控制。通过WPF的组件化开发,消息订阅,IOC容器。大大降低了WPF项目的耦合,让我们可以将所有复杂的WPF 程序进行无限拆分。
#mermaid-svg-5wiXbIxQBuklT5uZ {font-family:”trebuchet ms”,verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-5wiXbIxQBuklT5uZ .error-icon{fill:#552222;}#mermaid-svg-5wiXbIxQBuklT5uZ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-5wiXbIxQBuklT5uZ .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-5wiXbIxQBuklT5uZ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-5wiXbIxQBuklT5uZ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-5wiXbIxQBuklT5uZ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-5wiXbIxQBuklT5uZ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-5wiXbIxQBuklT5uZ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-5wiXbIxQBuklT5uZ .marker.cross{stroke:#333333;}#mermaid-svg-5wiXbIxQBuklT5uZ svg{font-family:”trebuchet ms”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-5wiXbIxQBuklT5uZ .label{font-family:”trebuchet ms”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-5wiXbIxQBuklT5uZ .cluster-label text{fill:#333;}#mermaid-svg-5wiXbIxQBuklT5uZ .cluster-label span{color:#333;}#mermaid-svg-5wiXbIxQBuklT5uZ .label text,#mermaid-svg-5wiXbIxQBuklT5uZ span{fill:#333;color:#333;}#mermaid-svg-5wiXbIxQBuklT5uZ .node rect,#mermaid-svg-5wiXbIxQBuklT5uZ .node circle,#mermaid-svg-5wiXbIxQBuklT5uZ .node ellipse,#mermaid-svg-5wiXbIxQBuklT5uZ .node polygon,#mermaid-svg-5wiXbIxQBuklT5uZ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-5wiXbIxQBuklT5uZ .node .label{text-align:center;}#mermaid-svg-5wiXbIxQBuklT5uZ .node.clickable{cursor:pointer;}#mermaid-svg-5wiXbIxQBuklT5uZ .arrowheadPath{fill:#333333;}#mermaid-svg-5wiXbIxQBuklT5uZ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-5wiXbIxQBuklT5uZ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-5wiXbIxQBuklT5uZ .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-5wiXbIxQBuklT5uZ .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-5wiXbIxQBuklT5uZ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-5wiXbIxQBuklT5uZ .cluster text{fill:#333;}#mermaid-svg-5wiXbIxQBuklT5uZ .cluster span{color:#333;}#mermaid-svg-5wiXbIxQBuklT5uZ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:”trebuchet ms”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-5wiXbIxQBuklT5uZ :root{–mermaid-font-family:”trebuchet ms”,verdana,arial,sans-serif;} DataContext强绑定,依赖属性暴露 父子组件通讯,Message消息订阅 IOC构造 IOC取出 View ViewModel ViewA Services IOC容器