如何在WPF的MVVM视图模型中实现Autofac依赖注入?
解决WPF MVVM中Autofac依赖注入的子ViewModel创建问题
我之前也碰到过和你一模一样的困境——要么绕回ServiceLocator的老路子,要么把父ViewModel的构造函数塞得满满当当,层层传依赖简直头疼。后来发现Autofac的**委托工厂(Delegate Factories)**完美解决了这个问题,完全符合DI思想,还特别简洁,分享给你:
核心思路:用委托工厂让Autofac帮你创建子ViewModel
Autofac可以自动实现你定义的工厂委托,你只需要把工厂注入到父ViewModel里,调用工厂方法就能创建子ViewModel,所有依赖都会自动注入,根本不用你手动去resolve或者传参。
具体实现步骤
1. 给每个需要动态创建的ViewModel定义工厂委托
这些委托的签名要和ViewModel的构造函数完全匹配,Autofac会自动生成实现类:
// 对应HomePageViewModel的工厂 public delegate HomePageViewModel HomePageViewModelFactory(); // 对应MonitorPageViewModel的工厂 public delegate MonitorPageViewModel MonitorPageViewModelFactory(); // 对应MonitorDashboardViewModel的工厂 public delegate MonitorDashboardViewModel MonitorDashboardViewModelFactory(); // 对应ResourceManagementViewModel的工厂 public delegate ResourceManagementViewModel ResourceManagementViewModelFactory();
2. 父ViewModel只注入需要的工厂,不用再塞一堆服务
比如MainViewModel现在只需要注入各个子ViewModel的工厂,构造函数瞬间清爽:
public class MainViewModel : ViewModelBase { public ObservableCollection<DockPaneViewModel> DockPanes { get; set; } = new ObservableCollection<DockPaneViewModel>(); private readonly HomePageViewModelFactory _homePageFactory; private readonly MonitorPageViewModelFactory _monitorPageFactory; private readonly ResourceManagementViewModelFactory _resourceManagementFactory; public MainViewModel( HomePageViewModelFactory homePageFactory, MonitorPageViewModelFactory monitorPageFactory, ResourceManagementViewModelFactory resourceManagementFactory) { _homePageFactory = homePageFactory; _monitorPageFactory = monitorPageFactory; _resourceManagementFactory = resourceManagementFactory; } public void ResetPanes() { DockPanes.Clear(); // 直接调用工厂方法,Autofac自动注入所有依赖 DockPanes.Add(_homePageFactory()); DockPanes.Add(_monitorPageFactory()); DockPanes.Add(_resourceManagementFactory()); } }
3. 孙ViewModel的创建逻辑同理
比如MonitorPageViewModel需要创建MonitorDashboardViewModel,只需要注入对应的工厂就行,不用再操心依赖怎么来:
public class MonitorPageViewModel : DockPaneViewModel { private readonly MonitorDashboardViewModelFactory _dashboardFactory; // 只保留自身需要的依赖 + 孙ViewModel的工厂 public MonitorPageViewModel( ILogger logger, IRepository<RawMessage> repository, IRepository<Parser> parserRepository, IParsingService parsingService, MonitorDashboardViewModelFactory dashboardFactory) { _dashboardFactory = dashboardFactory; // 你的初始化逻辑 } public void CreateDashboard() { // 一句话创建孙ViewModel,依赖自动搞定 var dashBoardVm = _dashboardFactory(); // 后续逻辑,比如添加到你的集合里 } }
4. 容器注册完全不用改(除了ViewModel本身)
Autofac会自动识别并实现你定义的工厂委托,所以注册的时候只需要正常注册服务和ViewModel就行:
var builder = new ContainerBuilder(); // 注册你的服务实现(这里假设你有对应的实现类) builder.RegisterType<Logger>().As<ILogger>(); builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>)); builder.RegisterType<ParsingService>().As<IParsingService>(); builder.RegisterType<StatisticsService>().As<IStatisticsService>(); // 注册所有ViewModel builder.RegisterType<MainViewModel>(); builder.RegisterType<HomePageViewModel>(); builder.RegisterType<MonitorPageViewModel>(); builder.RegisterType<MonitorDashboardViewModel>(); builder.RegisterType<ResourceManagementViewModel>(); var container = builder.Build();
为什么这个方案比你之前的两种好?
- 完全符合DI原则:既没有直接操作容器(避免了ServiceLocator反模式),也不用层层传递依赖,每个ViewModel只关心自己需要的东西。
- 构造函数清爽:再也不会出现一堆服务参数的情况,维护起来特别方便。
- 灵活性强:如果以后某个ViewModel的构造函数改了,只需要调整对应的工厂委托(如果签名变了的话),其他代码完全不用动。
- 原生支持:这是Autofac自带的功能,不用额外加任何MVVM框架,完全符合你不想用Caliburn.Micro的需求。
额外优化:用泛型工厂减少重复代码(可选)
如果你的ViewModel特别多,不想一个个写工厂委托,可以用泛型工厂:
public delegate T ViewModelFactory<T>() where T : DockPaneViewModel;
然后在MainViewModel里注入ViewModelFactory<HomePageViewModel>、ViewModelFactory<MonitorPageViewModel>这类泛型工厂就行,能省不少重复代码。
内容的提问来源于stack exchange,提问作者ricky
相关产品推荐
相关产品推荐

