ViewModelLocator
是实现 View 和 ViewModel 自动关联 的核心机制。当你在
XAML
中设置:
prism:ViewModelLocator.AutoWireViewModel="True"
Prism 会根据 约定(Convention) 自动解析并绑定 View 和对应的 ViewModel,而不需要手动实例化 ViewModel。
📌 实现原理概述
-
依附属性(Attached Property)机制
Prism 通过依附属性AutoWireViewModel
监听 View 的加载(Loaded
事件),在 View 加载时触发自动绑定。 -
ViewModel 解析与创建
Prism 通过约定(View/ViewModel 命名规则)和 IoC 容器(如 Unity、DryIoc)解析出 ViewModel 类型,并创建实例。 -
ViewModel 设置
Prism 将解析得到的 ViewModel 设置为 View 的DataContext
,实现 View 和 ViewModel 绑定。
📖 源码解析
1️⃣ AutoWireViewModel
属性注册
Prism 在 ViewModelLocator
类中定义了一个 依附属性,用于自动绑定:
public static readonly DependencyProperty AutoWireViewModelProperty = DependencyProperty.RegisterAttached( "AutoWireViewModel", typeof(bool?), typeof(ViewModelLocator), new PropertyMetadata(null, AutoWireViewModelChanged) );
DependencyProperty.RegisterAttached
是 WPF 定义依附属性的 API。AutoWireViewModelChanged
是属性变更时的回调函数,触发 ViewModel 自动绑定逻辑。
2️⃣ 属性变更触发逻辑
当 AutoWireViewModel
被设置为 True
时,执行以下绑定过程:
private static void AutoWireViewModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if ((bool?)e.NewValue == true) { SetAutowireViewModel(d); } }
d
表示目标对象(通常是FrameworkElement
)。SetAutowireViewModel(d)
是关键绑定逻辑,负责解析和注入 ViewModel。
3️⃣ ViewModel 自动绑定逻辑
private static void SetAutowireViewModel(object view) { var viewModel = GetViewModelForView(view); if (viewModel != null) { ((FrameworkElement)view).DataContext = viewModel; } }
- 调用
GetViewModelForView()
解析 ViewModel 类型并创建实例。 - 将 ViewModel 设置为 View 的
DataContext
,完成绑定。
🔍 ViewModel 解析逻辑
(1) 命名约定解析
Prism 默认使用以下命名规则解析 ViewModel:
- View →
MainWindow
- ViewModel →
MainWindowViewModel
代码实现如下:
protected static object GetViewModelForView(object view) { var viewType = view.GetType(); var viewName = viewType.FullName; var viewAssemblyName = viewType.GetTypeInfo().Assembly.FullName; // 默认根据约定推断 ViewModel 名称 var viewModelName = viewName.Replace("View", "ViewModel"); var viewModelType = Type.GetType($"{viewModelName}, {viewAssemblyName}"); return viewModelType != null ? Activator.CreateInstance(viewModelType) : null; }
- ViewModel 名称推导:将
View
替换为ViewModel
。 - Type.GetType:根据完全限定名反射获取类型。
- Activator.CreateInstance:使用无参数构造函数创建 ViewModel 实例。
(2) 依赖注入解析(IoC 容器)
如果你使用 Prism 的依赖注入(Unity、DryIoc 等),Prism 优先通过 IoC 容器解析 ViewModel:
var viewModelType = Type.GetType(viewModelName); if (viewModelType != null && ContainerLocator.Container != null) { return ContainerLocator.Container.Resolve(viewModelType); }
- ContainerLocator.Container:Prism 全局 IoC 容器。
- Resolve():根据类型解析 ViewModel,支持构造函数注入。
📊 工作流程总结
- View 加载:View 被实例化并加载到界面。
- 属性变化回调:设置
AutoWireViewModel="True"
触发绑定逻辑。 - ViewModel 解析:
- 按 命名约定(View → ViewModel)查找 ViewModel 类型。
- 使用 IoC 容器(若有)解析 ViewModel,支持依赖注入。
- DataContext 设置:将 ViewModel 作为
DataContext
设置到 View
📚 示例:完整实现
1️⃣ MainWindow.xaml
<Window x:Class="PrismDemo.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:prism="http://prismlibrary.com/" prism:ViewModelLocator.AutoWireViewModel="True"> <Grid> <TextBlock Text="{Binding Title}" FontSize="24" /> </Grid> </Window>
2️⃣ MainWindowViewModel.cs
public class MainWindowViewModel : BindableBase { private string _title = "Hello Prism!"; public string Title { get => _title; set => SetProperty(ref _title, value); } }
3️⃣ App.xaml.cs
public class App : PrismApplication { protected override Window CreateShell() => Container.Resolve<MainWindow>(); protected override void RegisterTypes(IContainerRegistry containerRegistry) { containerRegistry.RegisterSingleton<MainWindowViewModel>(); } }
📌 自定义 View-ViewModel 绑定策略
你可以通过覆盖 ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver
自定义解析规则。例如,使用 VM
后缀
ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver(viewType => { var viewName = viewType.FullName.Replace("View", "VM"); return Type.GetType(viewName); });
✅ 总结:prism:ViewModelLocator.AutoWireViewModel
通过 依附属性 触发,结合 View/ViewModel 命名约定 和 IoC 容器解析,
实现 View 和 ViewModel 的自动绑定。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)