依赖注入(Dependency Injection, DI)是 Prism 框架中实现模块化架构和松耦合设计的关键机制,通过将对象的依赖关系交由外部容器
依赖注入(Dependency Injection, DI)是 Prism 框架中实现模块化架构和松耦合设计的关键机制,通过将对象的依赖关系交由外部容器(如 Autofac 或 Unity)管理,降低模块、视图和 ViewModel 之间的耦合性。结合您提供的 WpfPowerTester 项目代码(App.xaml.cs、ModuleAModule.cs、ModuleBModule.cs 和 TestProgramView.xaml),我将深入讲解 Prism 的依赖注入机制,包括核心概念、工作原理、在您代码中的应用、优化实现方式,以及与事件聚合、多区域导航和动态模块加载的集成(基于之前的讨论)。还将提供代码示例,修复 TestProgramView.xaml 的问题,并展示高级依赖注入场景(如生命周期管理、工厂模式和条件注入)。
1. 依赖注入机制的核心概念
依赖注入是一种设计模式,通过外部容器提供对象所需的依赖,而不是对象自行创建。Prism 利用 DI 容器(如 Autofac)管理模块、视图、ViewModel 和服务的生命周期和依赖关系。以下是核心概念:
1.1 IoC 容器(Inversion of Control Container)
- 定义:IoC 容器负责创建和管理对象,解析其依赖关系。
- Prism 接口:
IContainerRegistry:用于注册类型和服务。IContainerProvider:用于解析类型和服务。
- 实现:
- Prism 支持 Unity、Autofac、DryIoc 等容器。
- 您的代码使用 Autofac(
AutofacContainerExtension)。
- 示例(来自您的代码):
containerRegistry.RegisterSingleton<ILoggingService, LoggingService>();
1.2 依赖注入方式
- 构造函数注入:通过构造函数传递依赖(最常见)。
- 示例:
public ModuleAModule(IEventAggregator eventAggregator, ILoggingService loggingService) { _eventAggregator = eventAggregator; _loggingService = loggingService; }
- 示例:
- 属性注入:通过属性设置依赖(较少使用)。
- 方法注入:通过方法参数传递依赖(动态场景)。
1.3 服务注册
- 方式:
Register<TInterface, TImplementation>():注册接口和实现。RegisterSingleton<TInterface, TImplementation>():注册单例。RegisterInstance<T>(instance):注册现有实例。RegisterForNavigation<TView, TViewModel>():注册视图和 ViewModel。
- 作用:定义依赖的映射和生命周期。
- 示例(来自您的代码):
containerRegistry.RegisterForNavigation<TestProgramView, TestProgramViewModel>();
1.4 生命周期管理
- 瞬态(Transient):每次解析创建新实例。
- 单例(Singleton):全局唯一实例。
- 作用域(Scoped):在特定作用域(如 HTTP 请求或导航)内共享实例。
- Prism 默认:
RegisterSingleton使用单例,Register使用瞬态。 - 示例:
builder.RegisterType<LoggingService>().As<ILoggingService>().SingleInstance();
1.5 模块化支持
- 定义:模块通过
RegisterTypes(IContainerRegistry)注册自己的服务和视图。 - 作用:支持动态模块加载,模块独立管理依赖。
- 示例(来自
ModuleAModule):containerRegistry.RegisterSingleton<IHardwareService, HardwareService>();
1.6 与其他机制的集成
- 事件聚合:
IEventAggregator通过 DI 注入,模块通过事件通信。 - 区域导航:
IRegionManager注入 ViewModel,触发导航。 - 动态模块加载:IoC 容器解析动态模块的依赖。
- 示例(来自您的代码):
public ModuleAModule(IEventAggregator eventAggregator, ILoggingService loggingService)
1.7 优点
- 松耦合:模块依赖接口而非具体实现。
- 可测试性:便于单元测试,注入模拟对象。
- 可扩展性:动态模块可注册新服务。
- 可维护性:集中管理依赖关系。
1.8 缺点
- 复杂性:需要配置容器和注册服务。
- 性能开销:依赖解析可能增加启动时间。
- 学习曲线:开发者需熟悉 DI 容器(如 Autofac)。
2. 依赖注入的工作原理
Prism 的依赖注入流程如下:
- 注册服务:
- 在
App.xaml.cs或模块的RegisterTypes中注册类型(如ILoggingService)。
- 在
- 依赖解析:
- IoC 容器(如 Autofac)根据注册的映射解析依赖。
- 注入依赖:
- 通过构造函数、属性或方法注入依赖(如
IEventAggregator)。
- 通过构造函数、属性或方法注入依赖(如
- 对象创建:
- 容器创建对象,递归解析其依赖。
- 生命周期管理:
- 容器根据注册方式(瞬态、单例)管理对象生命周期。
- 导航集成:
- 导航到视图时,容器解析 ViewModel 并设置
DataContext。
- 导航到视图时,容器解析 ViewModel 并设置
3. 在您代码中的依赖注入应用
结合您的代码(App.xaml.cs、ModuleAModule.cs、ModuleBModule.cs 和 TestProgramView.xaml),分析依赖注入的应用:
3.1 服务注册
-
App.xaml.cs:
protected override void RegisterTypes(IContainerRegistry containerRegistry) { containerRegistry.RegisterSingleton<ILoggingService, LoggingService>(); containerRegistry.RegisterSingleton<IEventAggregator, EventAggregator>(); containerRegistry.RegisterForNavigation<TestProgramView, TestProgramViewModel>(); }- 分析:
- 注册全局单例服务(如
ILoggingService、IEventAggregator)。 - 注册导航视图和 ViewModel。
- 注册全局单例服务(如
- 分析:
-
ModuleAModule:
public void RegisterTypes(IContainerRegistry containerRegistry) { containerRegistry.RegisterSingleton<IHardwareService, HardwareService>(); containerRegistry.RegisterSingleton<IKFactorService, KFactorService>(); }- 分析:模块注册自己的服务,支持跨模块使用。
3.2 构造函数注入
- ModuleAModule:
public ModuleAModule(IEventAggregator eventAggregator, ILoggingService loggingService) { _eventAggregator = eventAggregator; _loggingService = loggingService; }- 分析:通过构造函数注入全局服务。
3.3 TestProgramView 的问题
- TestProgramView.xaml:
<UserControl.DataContext> <vm:TestProgramViewModel /> </UserControl.DataContext>- 问题:
- 直接实例化
TestProgramViewModel,绕过 IoC 容器,无法注入依赖(如ILoggingService、IEventAggregator)。 - 不支持区域导航和事件聚合。
- 直接实例化
- 解决方案:移除 XAML 中的
DataContext,依赖 Prism 导航。
- 问题:
3.4 动态模块加载
- App.xaml.cs:
var directoryCatalog = new DirectoryModuleCatalog { ModulePath = modulePath }; directoryCatalog.Load();- 分析:
- 动态模块通过
RegisterTypes注册服务,容器解析依赖。 - 依赖注入支持动态模块的松耦合通信。
- 动态模块通过
- 分析:
4. 实现依赖注入与多区域导航和事件聚合
以下是优化依赖注入的实现步骤,修复 TestProgramView.xaml,添加新模块 ModuleC,并集成多区域导航、事件聚合和动态模块加载。
4.1 定义事件和服务
Core/Events.cs:
using Prism.Events;
namespace WpfPowerTester.Core
{
public class DeviceAddedEvent : PubSubEvent<DeviceAddedEventArgs> { }
public class DeviceAddedEventArgs
{
public string DeviceId { get; set; }
}
public class ContentNavigatedEvent : PubSubEvent<string> { }
}
Core/Services/ILoggingService.cs(假设定义):
namespace WpfPowerTester.Core.Services
{
public interface ILoggingService
{
void LogInfo(string message);
void LogError(string message);
}
public class LoggingService : ILoggingService
{
public void LogInfo(string message) => Console.WriteLine($"INFO: {message}");
public void LogError(string message) => Console.WriteLine($"ERROR: {message}");
}
}
4.2 创建 ModuleC
项目:WpfPowerTester.ModuleC(生成 WpfPowerTester.ModuleC.dll,输出到 bin\Modules)
ModuleCModule.cs:
using Prism.Ioc;
using Prism.Modularity;
using Prism.Regions;
using WpfPowerTester.Core;
using WpfPowerTester.Core.Services;
using WpfPowerTester.ModuleA;
namespace WpfPowerTester.ModuleC
{
public class ModuleCModule : IModule
{
private readonly ILoggingService _loggingService;
private readonly IHardwareService _hardwareService;
private readonly IRegionManager _regionManager;
private readonly IEventAggregator _eventAggregator;
public ModuleCModule(ILoggingService loggingService, IHardwareService hardwareService, IRegionManager regionManager, IEventAggregator eventAggregator)
{
_loggingService = loggingService;
_hardwareService = hardwareService;
_regionManager = regionManager;
_eventAggregator = eventAggregator;
}
public void OnInitialized(IContainerProvider containerProvider)
{
_loggingService.LogInfo($"ModuleC initialized with hardware: {_hardwareService.GetHardwareInfo()}");
_eventAggregator.GetEvent<DeviceAddedEvent>().Subscribe(OnDeviceAdded, ThreadOption.UIThread, false, args => args.DeviceId.StartsWith("C"));
_regionManager.RequestNavigate("ContentRegion", nameof(ModuleCView));
_regionManager.RequestNavigate("SidebarRegion", nameof(ModuleCSidebarView));
_eventAggregator.GetEvent<DeviceAddedEvent>().Publish(new DeviceAddedEventArgs { DeviceId = "C123" });
}
private void OnDeviceAdded(DeviceAddedEventArgs args)
{
_loggingService.LogInfo($"ModuleC received DeviceAddedEvent: {args.DeviceId}");
}
public void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterSingleton<IModuleCService, ModuleCService>();
containerRegistry.RegisterForNavigation<ModuleCView, ModuleCViewModel>();
containerRegistry.RegisterForNavigation<ModuleCSidebarView, ModuleCSidebarViewModel>();
}
}
public interface IModuleCService
{
string GetData();
}
public class ModuleCService : IModuleCService
{
public string GetData() => "ModuleC Data";
}
}
ModuleCView.xaml:
<UserControl x:Class="WpfPowerTester.ModuleC.ModuleCView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/">
<Grid>
<StackPanel>
<TextBlock Text="ModuleC Main View" FontSize="20" />
<TextBlock Text="{Binding Data}" />
</StackPanel>
</Grid>
</UserControl>
ModuleCViewModel.cs:
using Prism.Mvvm;
using Prism.Navigation;
using WpfPowerTester.Core;
using WpfPowerTester.Core.Services;
namespace WpfPowerTester.ModuleC
{
public class ModuleCViewModel : BindableBase, INavigationAware
{
private readonly ILoggingService _loggingService;
private readonly IModuleCService _moduleCService;
private readonly IEventAggregator _eventAggregator;
private string _data;
public ModuleCViewModel(ILoggingService loggingService, IModuleCService moduleCService, IEventAggregator eventAggregator)
{
_loggingService = loggingService;
_moduleCService = moduleCService;
_eventAggregator = eventAggregator;
_eventAggregator.GetEvent<DeviceAddedEvent>().Subscribe(OnDeviceAdded, ThreadOption.UIThread);
}
public string Data
{
get => _data;
set => SetProperty(ref _data, value);
}
private void OnDeviceAdded(DeviceAddedEventArgs args)
{
_loggingService.LogInfo($"ModuleCView received DeviceAddedEvent: {args.DeviceId}");
Data = $"Device Added: {args.DeviceId}";
}
public void OnNavigatedTo(INavigationParameters parameters)
{
_loggingService.LogInfo("Navigated to ModuleCView.");
Data = _moduleCService.GetData();
}
public void OnNavigatedFrom(INavigationParameters parameters) { }
public bool IsNavigationTarget(INavigationParameters parameters) => true;
}
}
ModuleCSidebarView.xaml:
<UserControl x:Class="WpfPowerTester.ModuleC.ModuleCSidebarView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/">
<Grid>
<StackPanel>
<TextBlock Text="ModuleC Sidebar" FontSize="16" />
<TextBlock Text="{Binding Status}" />
</StackPanel>
</Grid>
</UserControl>
ModuleCSidebarViewModel.cs:
using Prism.Mvvm;
using Prism.Navigation;
using Prism.Events;
using WpfPowerTester.Core;
namespace WpfPowerTester.ModuleC
{
public class ModuleCSidebarViewModel : BindableBase, INavigationAware
{
private readonly IEventAggregator _eventAggregator;
private string _status;
public ModuleCSidebarViewModel(IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
_eventAggregator.GetEvent<ContentNavigatedEvent>().Subscribe(OnContentNavigated, ThreadOption.UIThread);
}
public string Status
{
get => _status;
set => SetProperty(ref _status, value);
}
private void OnContentNavigated(string viewName)
{
Status = $"Main view navigated to: {viewName}";
}
public void OnNavigatedTo(INavigationParameters parameters)
{
Status = "ModuleC Sidebar loaded.";
}
public void OnNavigatedFrom(INavigationParameters parameters) { }
public bool IsNavigationTarget(INavigationParameters parameters) => true;
}
}
4.3 修改 ModuleAModule
使用 DI 注入服务:
using Prism.Ioc;
using Prism.Modularity;
using Prism.Events;
using WpfPowerTester.Core;
using WpfPowerTester.Core.Services;
namespace WpfPowerTester.ModuleA
{
public class ModuleAModule : IModule
{
private readonly IEventAggregator _eventAggregator;
private readonly ILoggingService _loggingService;
public ModuleAModule(IEventAggregator eventAggregator, ILoggingService loggingService)
{
_eventAggregator = eventAggregator;
_loggingService = loggingService;
}
public void OnInitialized(IContainerProvider containerProvider)
{
_eventAggregator.GetEvent<DeviceAddedEvent>().Subscribe(OnDeviceAdded, ThreadOption.UIThread);
_eventAggregator.GetEvent<DeviceAddedEvent>().Publish(new DeviceAddedEventArgs { DeviceId = "A123" });
}
private void OnDeviceAdded(DeviceAddedEventArgs args)
{
_loggingService.LogInfo($"ModuleA received DeviceAddedEvent: {args.DeviceId}");
}
public void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterSingleton<IHardwareService, HardwareService>();
containerRegistry.RegisterSingleton<IKFactorService, KFactorService>();
}
}
}
4.4 定义模块依赖
In app.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="modules" type="Prism.Modularity.ModulesConfigurationSection, Prism.Wpf" />
</configSections>
<modules>
<module assemblyFile="WpfPowerTester.ModuleA.dll" moduleType="WpfPowerTester.ModuleA.ModuleAModule, WpfPowerTester.ModuleA" moduleName="ModuleAModule" />
<module assemblyFile="WpfPowerTester.ModuleB.dll" moduleType="WpfPowerTester.ModuleB.ModuleBModule, WpfPowerTester.ModuleB" moduleName="ModuleBModule" />
<module assemblyFile="WpfPowerTester.ModuleC.dll" moduleType="WpfPowerTester.ModuleC.ModuleCModule, WpfPowerTester.ModuleC" moduleName="ModuleCModule" startupLoaded="false">
<dependencies>
<dependency moduleName="ModuleAModule" />
</dependencies>
</module>
</modules>
</configuration>
4.5 修改 TestProgramView.xaml
修复 DataContext:
<UserControl x:Class="WpfPowerTester.Views.TestProgramView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/">
<Grid>
<StackPanel>
<TextBlock Text="测试程序维护" FontSize="20" />
<TextBlock Text="{Binding StatusMessage}" />
<Button Content="加载并导航到 ModuleC" Command="{Binding LoadAndNavigateToModuleCCommand}" />
<Button Content="发布设备添加事件" Command="{Binding PublishDeviceAddedCommand}" />
<Button Content="返回" Command="{Binding GoBackCommand}" />
</StackPanel>
</Grid>
</UserControl>
4.6 修改 TestProgramViewModel
支持 DI、导航和事件:
using Prism.Commands;
using Prism.Mvvm;
using Prism.Navigation;
using Prism.Regions;
using Prism.Events;
using WpfPowerTester.Core;
using WpfPowerTester.Core.Services;
namespace WpfPowerTester.ViewModels
{
public class TestProgramViewModel : BindableBase, INavigationAware, IConfirmNavigationRequest
{
private readonly ILoggingService _loggingService;
private readonly IRegionManager _regionManager;
private readonly IModuleManager _moduleManager;
private readonly IEventAggregator _eventAggregator;
private string _statusMessage = "(待实现:配置测试参数)";
private SubscriptionToken _deviceAddedToken;
public TestProgramViewModel(ILoggingService loggingService, IRegionManager regionManager, IModuleManager moduleManager, IEventAggregator eventAggregator)
{
_loggingService = loggingService;
_regionManager = regionManager;
_moduleManager = moduleManager;
_eventAggregator = eventAggregator;
LoadAndNavigateToModuleCCommand = new DelegateCommand(LoadAndNavigateToModuleC);
PublishDeviceAddedCommand = new DelegateCommand(PublishDeviceAdded);
GoBackCommand = new DelegateCommand(GoBack);
}
public string StatusMessage
{
get => _statusMessage;
set => SetProperty(ref _statusMessage, value);
}
public DelegateCommand LoadAndNavigateToModuleCCommand { get; }
public DelegateCommand PublishDeviceAddedCommand { get; }
public DelegateCommand GoBackCommand { get; }
private void LoadAndNavigateToModuleC()
{
_loggingService.LogInfo("Loading ModuleC...");
_moduleManager.LoadModule("ModuleCModule");
_regionManager.RequestNavigate("ContentRegion", "ModuleCView", result =>
{
if (result.Result == true)
{
_loggingService.LogInfo($"Navigated to ModuleCView at {DateTime.Now}");
_eventAggregator.GetEvent<ContentNavigatedEvent>().Publish(nameof(ModuleCView));
}
});
}
private void PublishDeviceAdded()
{
_eventAggregator.GetEvent<DeviceAddedEvent>().Publish(new DeviceAddedEventArgs { DeviceId = "T123" });
_loggingService.LogInfo("Published DeviceAddedEvent: T123");
}
private void GoBack()
{
var region = _regionManager.Regions["ContentRegion"];
if (region.NavigationService.Journal.CanGoBack)
{
region.NavigationService.Journal.GoBack();
_eventAggregator.GetEvent<ContentNavigatedEvent>().Publish("Back");
}
}
public void OnNavigatedTo(INavigationParameters parameters)
{
_loggingService.LogInfo($"Navigated to TestProgramView at {DateTime.Now}");
if (parameters.TryGetValue<string>("DeviceId", out var deviceId))
{
StatusMessage = $"配置测试参数:器件 ID {deviceId}";
}
_deviceAddedToken = _eventAggregator.GetEvent<DeviceAddedEvent>().Subscribe(OnDeviceAdded, ThreadOption.UIThread, false, args => args.DeviceId.StartsWith("T"));
_eventAggregator.GetEvent<ContentNavigatedEvent>().Publish(nameof(TestProgramView));
}
private void OnDeviceAdded(DeviceAddedEventArgs args)
{
_loggingService.LogInfo($"TestProgramView received DeviceAddedEvent: {args.DeviceId}");
StatusMessage = $"Device Added: {args.DeviceId}";
}
public void OnNavigatedFrom(INavigationParameters parameters)
{
_eventAggregator.GetEvent<DeviceAddedEvent>().Unsubscribe(_deviceAddedToken);
}
public bool IsNavigationTarget(INavigationParameters parameters) => true;
public void ConfirmNavigationRequest(INavigationParameters parameters, Action<bool> continuationCallback)
{
bool canNavigate = MessageBox.Show("确认离开当前视图?", "确认", MessageBoxButton.YesNo) == MessageBoxResult.Yes;
continuationCallback(canNavigate);
}
}
}
4.7 修改 MainWindow.xaml
支持多区域:
<Window x:Class="WpfPowerTester.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ContentControl Grid.Column="0" prism:RegionManager.RegionName="SidebarRegion" />
<StackPanel Grid.Column="1">
<Button Content="导航到测试程序" Command="{Binding NavigateCommand}" />
<ContentControl prism:RegionManager.RegionName="ContentRegion" />
</StackPanel>
</Grid>
</Window>
4.8 修改 MainWindowViewModel
支持 DI 和导航:
using Prism.Commands;
using Prism.Mvvm;
using Prism.Regions;
using Prism.Events;
using WpfPowerTester.Core;
namespace WpfPowerTester.ViewModels
{
public class MainWindowViewModel : BindableBase
{
private readonly IRegionManager _regionManager;
private readonly IEventAggregator _eventAggregator;
public MainWindowViewModel(IRegionManager regionManager, IEventAggregator eventAggregator)
{
_regionManager = regionManager;
_eventAggregator = eventAggregator;
NavigateCommand = new DelegateCommand(Navigate);
_eventAggregator.GetEvent<DeviceAddedEvent>().Subscribe(OnDeviceAdded, ThreadOption.UIThread);
}
public DelegateCommand NavigateCommand { get; }
private void OnDeviceAdded(DeviceAddedEventArgs args)
{
// 可触发导航或其他逻辑
}
private void Navigate()
{
var parameters = new NavigationParameters { { "DeviceId", "123" } };
_regionManager.RequestNavigate("ContentRegion", nameof(TestProgramView), parameters);
_regionManager.RequestNavigate("SidebarRegion", nameof(TestProgramSidebarView));
}
}
}
TestProgramSidebarView.xaml:
<UserControl x:Class="WpfPowerTester.Views.TestProgramSidebarView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/">
<Grid>
<StackPanel>
<TextBlock Text="TestProgram Sidebar" FontSize="16" />
<TextBlock Text="{Binding Status}" />
</StackPanel>
</Grid>
</UserControl>
TestProgramSidebarViewModel.cs:
using Prism.Mvvm;
using Prism.Navigation;
using Prism.Events;
using WpfPowerTester.Core;
namespace WpfPowerTester.ViewModels
{
public class TestProgramSidebarViewModel : BindableBase, INavigationAware
{
private readonly IEventAggregator _eventAggregator;
private string _status;
public TestProgramSidebarViewModel(IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
_eventAggregator.GetEvent<ContentNavigatedEvent>().Subscribe(OnContentNavigated, ThreadOption.UIThread);
_eventAggregator.GetEvent<DeviceAddedEvent>().Subscribe(OnDeviceAdded, ThreadOption.UIThread);
}
public string Status
{
get => _status;
set => SetProperty(ref _status, value);
}
private void OnContentNavigated(string viewName)
{
Status = $"Main view navigated to: {viewName}";
}
private void OnDeviceAdded(DeviceAddedEventArgs args)
{
Status = $"Device Added: {args.DeviceId}";
}
public void OnNavigatedTo(INavigationParameters parameters)
{
Status = "TestProgram Sidebar loaded.";
}
public void OnNavigatedFrom(INavigationParameters parameters) { }
public bool IsNavigationTarget(INavigationParameters parameters) => true;
}
}
4.9 修改 App.xaml.cs
支持 DI 和多区域导航:
using Autofac;
using Prism.Autofac;
using Prism.Ioc;
using Prism.Modularity;
using System.IO;
using System.Windows;
namespace WpfPowerTester
{
public partial class App : PrismApplication
{
protected override Window CreateShell()
{
return Container.Resolve<MainWindow>();
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
var builder = containerRegistry.GetBuilder() as Autofac.ContainerBuilder;
builder.RegisterType<LoggingService>().As<ILoggingService>().SingleInstance();
builder.RegisterType<RegionManager>().As<IRegionManager>().SingleInstance();
builder.RegisterType<EventAggregator>().As<IEventAggregator>().SingleInstance();
builder.RegisterType<ModuleManager>().As<IModuleManager>().SingleInstance();
containerRegistry.RegisterForNavigation<MainWindow, MainWindowViewModel>();
containerRegistry.RegisterForNavigation<TestProgramView, TestProgramViewModel>();
containerRegistry.RegisterForNavigation<TestProgramSidebarView, TestProgramSidebarViewModel>();
}
protected override IContainerExtension CreateContainerExtension()
{
return new AutofacContainerExtension();
}
protected override IModuleCatalog CreateModuleCatalog()
{
return new ConfigurationModuleCatalog();
}
protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
{
try
{
string modulePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Modules");
if (Directory.Exists(modulePath))
{
var directoryCatalog = new DirectoryModuleCatalog { ModulePath = modulePath };
directoryCatalog.Load();
foreach (var moduleInfo in directoryCatalog.Modules)
{
moduleCatalog.AddModule(moduleInfo);
}
}
}
catch (Exception ex)
{
MessageBox.Show($"模块加载失败:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
}
5. 高级依赖注入场景
5.1 工厂模式
使用工厂动态创建服务:
public interface IServiceFactory
{
IModuleCService CreateModuleCService(string config);
}
public class ServiceFactory : IServiceFactory
{
private readonly IContainerProvider _containerProvider;
public ServiceFactory(IContainerProvider containerProvider)
{
_containerProvider = containerProvider;
}
public IModuleCService CreateModuleCService(string config)
{
var service = _containerProvider.Resolve<ModuleCService>();
// 配置 service(如果需要)
return service;
}
}
Register in App.xaml.cs:
builder.RegisterType<ServiceFactory>().As<IServiceFactory>().SingleInstance();
Use in ModuleCModule:
public class ModuleCModule : IModule
{
private readonly ILoggingService _loggingService;
private readonly IHardwareService _hardwareService;
private readonly IRegionManager _regionManager;
private readonly IEventAggregator _eventAggregator;
private readonly IServiceFactory _serviceFactory;
public ModuleCModule(ILoggingService loggingService, IHardwareService hardwareService, IRegionManager regionManager, IEventAggregator eventAggregator, IServiceFactory serviceFactory)
{
_loggingService = loggingService;
_hardwareService = hardwareService;
_regionManager = regionManager;
_eventAggregator = eventAggregator;
_serviceFactory = serviceFactory;
}
public void OnInitialized(IContainerProvider containerProvider)
{
var service = _serviceFactory.CreateModuleCService("customConfig");
_loggingService.LogInfo($"ModuleC initialized with service: {service.GetData()}");
_eventAggregator.GetEvent<DeviceAddedEvent>().Subscribe(OnDeviceAdded, ThreadOption.UIThread);
_regionManager.RequestNavigate("ContentRegion", nameof(ModuleCView));
}
private void OnDeviceAdded(DeviceAddedEventArgs args)
{
_loggingService.LogInfo($"ModuleC received DeviceAddedEvent: {args.DeviceId}");
}
public void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterSingleton<IModuleCService, ModuleCService>();
containerRegistry.RegisterForNavigation<ModuleCView, ModuleCViewModel>();
containerRegistry.RegisterForNavigation<ModuleCSidebarView, ModuleCSidebarViewModel>();
}
}
5.2 条件注入
根据条件注册服务:
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
var builder = containerRegistry.GetBuilder() as Autofac.ContainerBuilder;
builder.RegisterType<LoggingService>().As<ILoggingService>().SingleInstance();
builder.RegisterType<RegionManager>().As<IRegionManager>().SingleInstance();
builder.RegisterType<EventAggregator>().As<IEventAggregator>().SingleInstance();
builder.RegisterType<ModuleManager>().As<IModuleManager>().SingleInstance();
builder.RegisterType<ServiceFactory>().As<IServiceFactory>().SingleInstance();
// 条件注入
if (Environment.GetEnvironmentVariable("DEBUG") == "true")
{
builder.RegisterType<DebugLoggingService>().As<ILoggingService>().SingleInstance();
}
else
{
builder.RegisterType<LoggingService>().As<ILoggingService>().SingleInstance();
}
containerRegistry.RegisterForNavigation<MainWindow, MainWindowViewModel>();
containerRegistry.RegisterForNavigation<TestProgramView, TestProgramViewModel>();
containerRegistry.RegisterForNavigation<TestProgramSidebarView, TestProgramSidebarViewModel>();
}
DebugLoggingService.cs:
namespace WpfPowerTester.Core.Services
{
public class DebugLoggingService : ILoggingService
{
public void LogInfo(string message) => Console.WriteLine($"DEBUG INFO: {message}");
public void LogError(string message) => Console.WriteLine($"DEBUG ERROR: {message}");
}
}
5.3 作用域生命周期
使用 Autofac 的作用域:
public class ModuleCModule : IModule
{
private readonly ILoggingService _loggingService;
private readonly IHardwareService _hardwareService;
private readonly IRegionManager _regionManager;
private readonly IContainerProvider _containerProvider;
public ModuleCModule(ILoggingService loggingService, IHardwareService hardwareService, IRegionManager regionManager, IContainerProvider containerProvider)
{
_loggingService = loggingService;
_hardwareService = hardwareService;
_regionManager = regionManager;
_containerProvider = containerProvider;
}
public void OnInitialized(IContainerProvider containerProvider)
{
using (var scope = _containerProvider.CreateScope())
{
var service = scope.Resolve<IModuleCService>();
_loggingService.LogInfo($"ModuleC initialized with scoped service: {service.GetData()}");
}
_regionManager.RequestNavigate("ContentRegion", nameof(ModuleCView));
}
public void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.Register<IModuleCService, ModuleCService>().InstancePerLifetimeScope();
containerRegistry.RegisterForNavigation<ModuleCView, ModuleCViewModel>();
}
}
- 说明:
InstancePerLifetimeScope确保服务在特定作用域内共享。
6. 运行结果
-
启动:
- 应用程序加载
MainWindow,显示“导航到测试程序”按钮。 ModuleAModule通过 DI 注入ILoggingService和IEventAggregator,发布DeviceAddedEvent。
- 应用程序加载
-
导航到 TestProgramView:
- 点击“导航到测试程序”,
ContentRegion加载TestProgramView,SidebarRegion加载TestProgramSidebarView。 TestProgramViewModel注入ILoggingService、IRegionManager等,订阅DeviceAddedEvent。
- 点击“导航到测试程序”,
-
发布事件:
- 点击“发布设备添加事件”,触发
DeviceAddedEvent(DeviceId = "T123"),更新 UI。
- 点击“发布设备添加事件”,触发
-
加载 ModuleC:
- 点击“加载并导航到 ModuleC”,加载
ModuleCModule,注入IHardwareService(来自ModuleAModule)。 ModuleCView和ModuleCSidebarView加载,处理事件并同步导航状态。
- 点击“加载并导航到 ModuleC”,加载
-
返回:
- 点击“返回”,弹出确认对话框,恢复
TestProgramView。
- 点击“返回”,弹出确认对话框,恢复
7. 最佳实践
- 构造函数注入:
- 优先使用构造函数注入(如
ILoggingService),确保依赖明确。
- 优先使用构造函数注入(如
- 单例 vs 瞬态:
- 全局服务(如
ILoggingService)使用单例,视图相关服务使用瞬态或作用域。
- 全局服务(如
- 模块化注册:
- 模块在
RegisterTypes中注册服务,支持动态加载。
- 模块在
- 工厂模式:
- 使用工厂(如
IServiceFactory)动态创建服务。
- 使用工厂(如
- 条件注入:
- 根据环境(如
DEBUG)注册不同实现。
- 根据环境(如
- 作用域管理:
- 使用 Autofac 的作用域(如
InstancePerLifetimeScope)控制生命周期。
- 使用 Autofac 的作用域(如
- 异常处理:
- 捕获依赖解析异常,记录日志。
8. 总结
Prism 的依赖注入机制通过 IContainerRegistry 和 IContainerProvider 管理模块、视图和服务的依赖,与事件聚合、多区域导航和动态模块加载无缝集成。您的代码通过 Autofac 注册全局服务(如 ILoggingService)和模块服务(如 IHardwareService),但 TestProgramView.xaml 的 DataContext 问题需修复。通过添加 ModuleC、工厂模式和条件注入,展示了高级 DI 功能。事件聚合(DeviceAddedEvent)和多区域导航(ContentRegion、SidebarRegion)进一步增强了模块化架构。
如果您需要更复杂的 DI 场景(如拦截器、动态代理、复杂作用域)或 Autofac 的高级配置,请告诉我!
更多推荐



所有评论(0)