Prism.Unity.Forms中ContentView的ViewModel如何实现依赖注入?
嘿,我来帮你理清这个问题——Prism的依赖注入可不是只给ContentPage的ViewModel开绿灯哦!你遇到的异常其实是Prism默认的ViewModel定位逻辑范围限制导致的。
问题根源
Prism的ViewModelLocator默认只会自动为继承自Page的类型(比如ContentPage)完成ViewModel的匹配、实例化,并且自动从DI容器中注入依赖。但ContentView不属于Page体系,所以它的ViewModel不会被Prism自动接管,这就导致你的AboutViewModel在构造时,没法从容器中获取到IHomePageService实例,最终触发注入异常。而HomePage是ContentPage,刚好在默认处理范围内,所以注入正常。
解决方法
你有两种靠谱的方式解决这个问题,推荐第一种简单直接的方案:
方案1:手动通过DI容器解析ContentView的ViewModel
在你的About视图(ContentView)的后台代码中,注入Prism的IContainerProvider,手动解析ViewModel并绑定到BindingContext:
public partial class About : ContentView { private readonly AboutViewModel _viewModel; public About(IContainerProvider containerProvider) { InitializeComponent(); // 从DI容器中解析ViewModel,自动注入依赖 _viewModel = containerProvider.Resolve<AboutViewModel>(); BindingContext = _viewModel; } }
这样AboutViewModel就能正常获取到IHomePageService实例了。
方案2:扩展ViewModelLocator规则(进阶)
如果你希望让所有ContentView都能自动匹配ViewModel,可以在App.xaml.cs中扩展ViewModelLocator的处理规则:
protected override void ConfigureViewModelLocator() { base.ConfigureViewModelLocator(); // 注册单个ContentView与ViewModel的对应关系 ViewModelLocationProvider.Register<About, AboutViewModel>(); // 或者设置通用规则:自动匹配所有ContentView的ViewModel(按命名约定) ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver((viewType) => { if (typeof(ContentView).IsAssignableFrom(viewType)) { var viewName = viewType.FullName; var viewModelName = viewName.Replace("Views", "ViewModels") + "ViewModel"; return Type.GetType(viewModelName); } // 其他类型沿用默认规则 return ViewModelLocationProvider.DefaultViewTypeToViewModelTypeResolver(viewType); }); }
不过要注意,即使配置了通用规则,ContentView的ViewModel还是需要手动在后台通过容器解析(参考方案1的绑定步骤),因为ContentView不会像Page那样被Prism的导航系统自动初始化。
总结
核心就是:ContentView不在Prism默认的ViewModel自动处理范围内,只要手动借助DI容器解析ViewModel,依赖注入就能正常工作,和ContentPage的ViewModel待遇完全一致~
内容的提问来源于stack exchange,提问作者zs ou

