跳到主要内容

8.2 启动、容器与 ViewModelLocator

学习目标​

本篇创建一个最小 Prism 窗口,理解容器怎样构造 Shell,ViewModel 怎样成为 DataContext。它是一套独立入门练习;完整的多页面配套项目在 examples/PrismStudy,后续章节会加入模块与导航。

创建独立练习项目​

在一个新的练习目录中执行,避免覆盖已提供的 PrismStudy 源码。需要 Windows 与 .NET 10 SDK;安装运行时不能替代编译工具。

在单独的练习目录执行
dotnet new wpf -n PrismStudy --framework net10.0
cd PrismStudy
dotnet add package Prism.DryIoc --version 9.0.537

删除模板的 MainWindow.xaml 和 MainWindow.xaml.cs,创建 Views 与 ViewModels 两个目录。这里使用 Shell 作为主窗口名称;它表达的是应用外壳,通常放菜单、导航入口和内容区域。

把启动入口交给 Prism​

替换以下两个完整文件。App.xaml 的根类型与代码后置的基类要一致,并移除 StartupUri。否则默认 WPF 入口可能另外创建窗口,造成重复窗口或找不到已删除的模板文件。

App.xaml(完整文件)
<prism:PrismApplication x:Class="PrismStudy.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
ShutdownMode="OnMainWindowClose">
<Application.Resources />
</prism:PrismApplication>
App.xaml.cs(完整文件)
using System.Windows;
using Prism.DryIoc;
using Prism.Ioc;
using PrismStudy.ViewModels;
using PrismStudy.Views;

namespace PrismStudy;

public partial class App : PrismApplication
{
protected override Window CreateShell() => Container.Resolve<Shell>();

protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.Register<ShellViewModel>();
}
}

RegisterTypes 声明应用依赖;CreateShell 用容器解析主窗口。本例没有外部服务,只显式注册 ViewModel。DryIoc 的 Prism 适配器也可以解析具体类型;有接口依赖时,要注册接口和实现,不能期待容器凭名称猜实现。

它类似后端启动时的 builder.Services 和程序入口,但不会为每次点击创建请求作用域。此处采用默认的 WPF 主窗口关闭方式,没有 Generic Host 或后台任务;以后引入后台服务时,需要另外设计停止与释放流程。

关联 Shell 与 ViewModel​

创建以下三个完整文件。XAML 声明自动关联,代码后置只负责加载视图;不要在构造函数再 new ShellViewModel(),否则会绕开容器的依赖并可能覆盖自动关联结果。

Views/Shell.xaml(完整文件)
<Window x:Class="PrismStudy.Views.Shell"
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"
Title="Prism 入门" Width="640" Height="360">
<Grid Margin="24">
<TextBlock Text="{Binding Title}" FontSize="24"
VerticalAlignment="Center" HorizontalAlignment="Center" />
</Grid>
</Window>
Views/Shell.xaml.cs(完整文件)
using System.Windows;

namespace PrismStudy.Views;

public partial class Shell : Window
{
public Shell() => InitializeComponent();
}
ViewModels/ShellViewModel.cs(完整文件)
using Prism.Mvvm;

namespace PrismStudy.ViewModels;

public sealed class ShellViewModel : BindableBase
{
private string _title = "容器创建对象,绑定显示状态";

public string Title
{
get => _title;
set => SetProperty(ref _title, value);
}
}

约定把 PrismStudy.Views.Shell 对应到同一程序集内的 PrismStudy.ViewModels.ShellViewModel。目录帮助组织文件,实际解析依据是命名空间和类型名;文件夹名正确而命名空间错误,仍然无法匹配。

WPF 的 Region 导航和对话框流程通常会自动应用关联;普通视图注入不能统一假设有同样行为,所以这里在 Shell 上显式开启。需要脱离约定时,可以注册映射:

App.xaml.cs:ConfigureViewModelLocator 覆盖方法
protected override void ConfigureViewModelLocator()
{
base.ConfigureViewModelLocator();
Prism.Mvvm.ViewModelLocationProvider.Register<Shell, ShellViewModel>();
}

此方法片段加入上面的 App 类即可。后续 RegisterForNavigation<View, ViewModel> 和 RegisterDialog<View, ViewModel> 也会声明对应映射,便于功能模块维护配对关系。

容器注册与依赖边界​

本例的服务注册可在以后写成 RegisterSingleton<ITaskStore, InMemoryTaskStore>(),由页面通过构造函数接收。Singleton 表示应用共享实例,不表示自动线程安全;Transient 表示每次解析创建,不表示离开页面就一定释放。

不要让页面用静态全局容器随处解析服务。构造函数应暴露必要依赖,使页面可以用测试替身创建。已有 Generic Host 的应用迁移到 Prism 时,应先明确容器和资源所有者;简单教学项目由 Prism 容器负责创建依赖即可。

常见错误​

  • 主窗口没有显示绑定文字: 检查 AutoWireViewModel、命名空间、类型名,再在调试器检查 DataContext。
  • 构造函数依赖无法解析: 先核对接口注册,再核对 ViewModel 的创建方式。
  • 出现两个窗口: 检查模板 StartupUri 和自己额外调用的 Show();Prism 会管理 Shell 显示。
  • 旧教程类型找不到: 检查是否安装了容器适配包、是否使用 Prism.DryIoc 基类,并核对版本。

动手练习与验收​

执行 dotnet run,应显示“容器创建对象,绑定显示状态”。然后故意改错 ViewModel 命名空间,观察解析变化,再恢复或使用显式映射。

验收: 能画出 App → 容器 → Shell → ViewModel → DataContext → Binding 的关系;能解释构造函数没有手动设置 DataContext 为何仍显示文字。下一步学习Prism 通知与命令,再进入Region 导航。

官方资料​