WPF MVVM实战系列教程(四、Prism中的依赖注入)
⌨️ WPF MVVM实战系列教程
依赖注入
Prism 内置了对依赖注入的支持,默认使用Unity或DryIoc作为 DI 容器。其核心思想是:
- 将服务的创建和管理交给 DI 容器,而非手动
new - 通过构造函数注入、属性注入等方式获取依赖
- 支持服务的生命周期管理(
Transient、Singleton、Scoped)
本系列教程以Unity作为DI容器进行演示(DryIoc除了配置和注入时有点小区别,使用方面无异)
如果对依赖注入还不够了解,可以参考前面的文章
https://chuna2.787528.xyz/zhaotianff/p/18884247
https://chuna2.787528.xyz/zhaotianff/p/18515397
如何配置不同的DI容器
DryIoc
1、安装Prism.Wpf包和Prism.DryIoc包

2、修改App.xaml,将App类替换为Prism.DryIoc.PrismApplication类并移除StartupUri
1 <prism:PrismApplication x:Class="_12_Prism_Ioc.App" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:local="clr-namespace:_12_Prism_Ioc" 5 xmlns:prism="http://prismlibrary.com/"> 6 <Application.Resources> 7 8 </Application.Resources> 9 </prism:PrismApplication>
3、改造App类,使之继承自Prism.DryIoc.PrismApplication类
改造后的App类和前面介绍的Bootstrapper类结构一致
4、在RegisterTypes函数中注册类型到容器中
示例代码如下:
1 public partial class App : PrismApplication 2 { 3 // 1. 配置主窗口(Prism 启动时加载) 4 protected override Window CreateShell() 5 { 6 // DryIoc 会自动解析 MainWindow(依赖注入) 7 return Container.Resolve<MainWindow>(); 8 } 9 10 // 2. 注册服务到 DryIoc 容器 11 protected override void RegisterTypes(IContainerRegistry containerRegistry) 12 { 13 // ========== 基础注册方式 ========== 14 // 单例注册(全局唯一) 15 containerRegistry.RegisterSingleton<IMessageService, MessageService>(); 16 17 // 瞬时注册(每次解析新建实例) 18 containerRegistry.Register<IDataService, DataService>(); 19 20 // 若需要使用 DryIoc 原生 API,可通过 Container 转换 21 var dryIocContainer = containerRegistry.GetContainer(); 22 23 //dryIocContainer是DryIoc原生容器对象,可以参考DryIoc文档了解详细使用 24 //https://github.com/dadhi/DryIoc 25 26 // 注册视图(Prism 导航用) 27 containerRegistry.RegisterForNavigation<HomeView>(); 28 } 29 30 // 3. 可选:模块化配置(若使用模块) 31 protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog) 32 { 33 base.ConfigureModuleCatalog(moduleCatalog); 34 // 注册模块(示例) 35 // moduleCatalog.AddModule<MyModule>(); 36 } 37 }
Unity
1、安装Prism.Wpf包和Prism.Unity包

2、创建Bootstrapper类
1 public class Bootstrapper : PrismBootstrapper 2 { 3 protected override DependencyObject CreateShell() 4 { 5 return Container.Resolve<MainWindow>(); 6 } 7 8 protected override void RegisterTypes(IContainerRegistry containerRegistry) 9 { 10 11 } 12 }
3、移除App.xaml中的StartupUri

4、修改App类,重写Startup函数,启动Bootstrapper
1 public partial class App : Application 2 { 3 protected override void OnStartup(StartupEventArgs e) 4 { 5 base.OnStartup(e); 6 7 Bootstrapper bootstrapper = new Bootstrapper(); 8 bootstrapper.Run(); 9 } 10 }
Prism框架提供的服务
在前面介绍Bootstrapper的职责时,其中包含了一项自动初始化 Prism 的关键服务。
Prism框架为我们提供了以下服务
IRegionManager:管理视图区域(Region),实现视图的动态加载 / 切换;
IEventAggregator:实现模块间的无耦合通信;
IDialogService:统一管理对话框;
INavigationService:实现视图导航。
在Bootstrapper初始化时,框架会帮我们注入这些服务的实例到容器中。
后面我们在使用时,就可以直接从容器中去取。
这里暂时不做进一步演示,等介绍到对应的服务时,再进行演示。
如何注册自己的服务 / 视图
首先我们创建服务接口/类
1 // 服务接口 2 public interface IMessageService 3 { 4 string GetMessage(); 5 } 6 7 // 服务实现 8 public class MessageService : IMessageService 9 { 10 public string GetMessage() 11 { 12 return "Hello Prism DI!"; 13 } 14 } 15 16 // 服务实现2 17 public class MessageService2 : IMessageService 18 { 19 public string GetMessage() 20 { 21 return "Hello Prism DI 2222222!"; 22 } 23 }
然后在RegisterTypes函数中进行注册
1 protected override void RegisterTypes(IContainerRegistry containerRegistry) 2 { 3 containerRegistry.Register<IMessageService, MessageService>(); 4 }
Prism提供了三个注册类型的接口
Register:Transient,每次service请求都是获得不同的实例.
RegisterScoped:对于同一个请求返回同一个实例,不同的请求返回不同的实例.
RegisterSingleton:每次都是获得同一个实例, 单一实例模式.
此外,Prism还提供一种注册视图与 ViewModel(自动关联)的方式
这种方式在后面进行导航时会经常用到
1 protected override void RegisterTypes(IContainerRegistry containerRegistry) 2 { 3 containerRegistry.RegisterForNavigation<ViewA, ViewAViewModel>(); 4 }
如何使用Unity的原生接口
通过下面的语句,就可以获取Unity原生容器对象(DryIoc也是一样的方法)
1 var unityContainer = containerProvider.GetContainer()
Unity原生的注册方式会有点小区别,可以参考Unity的文档(https://github.com/UnityContainer/Unity)
1 unityContainer.RegisterType<IMessageService, MessageService>("Service1", new Unity.Lifetime.ContainerControlledLifetimeManager());
说明:Prism 的 IContainerRegistry 是 DI容器的封装,RegisterTypes 是注册服务的唯一推荐入口,不要在其他地方随意创建 DI容器实例。
如何注册同一个接口的不同实现
在前面我们实现了MessageService和MessageService2,但是只注册了MessageService。
如果要注册同一个接口的不同实现,我们可以通过给实例命名的方式实现
1 containerRegistry.Register<IMessageService, MessageService>("ServiceA"); 2 containerRegistry.Register<IMessageService, MessageService2>("ServiceB");
如何使用容器中注入的对象
在前面我们介绍CommunityToolkit中的Ioc时,是使用了手动从容器中去取的方法。
类似下面的形式
1 var messageService = containerRegistry.GetContainer().Resolve<IMessageService>();
在Prism中,推荐是使用构造函数注入的形式来获取容器中的对象,如下所示
1 public class MainWindowViewModel : BindableBase 2 { 3 private string _message; 4 public string Message 5 { 6 get => _message; 7 set => SetProperty(ref _message, value); 8 } 9 10 // 构造函数注入(Unity自动解析) 11 public MainWindowViewModel(IMessageService messageService) 12 { 13 Message = messageService.GetMessage(); 14 } 15 }
但是这种方式是有前提的,需要使用ViewModelLocator.AutoWireViewModel附加属性,将ViewModel自动绑定到View上。
当指定了ViewModelLocator.AutoWireViewModel=true时,Prism会帮我们自动将ViewModel和View进行绑定,这个功能在下一篇文章中会进行详细介绍。
注意:我们也可以把IContainerProvider进行注入,以便手动去容器中获取对象实例,如下所示。
但是不推荐这种方法,尽量使用构造函数自动注入的方式。
其中:IContainerProvider是Unity提供的解析接口,用于从容器中获取已注册的服务实例。
1 public MainWindowViewModel(IContainerProvider containerProvider) 2 { 3 //手动解析 4 var messageServiceB = containerProvider.Resolve<IMessageService>("ServiceB"); 5 }
如何指定注入的对象
在前面我们使用构造函数来获取注入的对象,那这种情况是系统控制的。如果我们使用的接口有两个实现,那如何获取指定的实例呢?
解决方法就是手动配置构造函数注入
这种情况需要使用Unity的原生接口,如下所示
1 protected override void RegisterTypes(IContainerRegistry containerRegistry) 2 { 3 //注册同一接口的不同实现 4 containerRegistry.Register<IMessageService, MessageService>("ServiceA"); 5 containerRegistry.Register<IMessageService, MessageService2>("ServiceB"); 6 7 //手动配置注入 8 containerRegistry.GetContainer().RegisterFactory<MainWindowViewModel>((container, type, name) => new MainWindowViewModel(container.Resolve<IMessageService>("ServiceB"))); 9 }
这样我们在MainWindowViewModel中使用时,获取的就是MessageService2的实例
1 public class MainWindowViewModel : BindableBase 2 { 3 private IMessageService messageService; 4 5 public MainWindowViewModel(IMessageService messageService) 6 { 7 this.messageService = messageService; 8 9 System.Windows.MessageBox.Show( messageService.GetMessage()); 10 } 11 }
运行效果

示例代码
https://github.com/zhaotianff/WPF-MVVM-Beginner/tree/main/12_Prism_Ioc

浙公网安备 33010602011771号