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 的自动绑定。
浙公网安备 33010602011771号