自定义引导程序
约 1184 字大约 4 分钟
Caliburn.MicroWPFC#.net
2025-06-19
在 基本配置、操作和约定 中,讨论了 Caliburn.Micro WPF 应用程序的最基本配置,并演示了一些与操作和约定相关的简单功能。在这一部分中,想进一步探索 Bootstrapper 类。
配置 IoC 容器
编辑 Bootstrapper
public class Bootstrapper : BootstrapperBase {
private SimpleContainer container;
public Bootstrapper() {
Initialize();
}
protected override async void OnStartup(object sender, StartupEventArgs e) {
await DisplayRootViewForAsync<ShellViewModel>();
}
protected override void Configure() {
container = new SimpleContainer();
container.Singleton<IWindowManager, WindowManager>();
container.Singleton<IEventAggregator, EventAggregator>();
container.PerRequest<ShellViewModel>();
}
protected override object GetInstance(Type service, string key) {
return container.GetInstance(service, key);
}
protected override IEnumerable<object> GetAllInstances(Type service) {
return container.GetAllInstances(service);
}
protected override void BuildUp(object instance) {
container.BuildUp(instance);
}
protected override IEnumerable<Assembly> SelectAssemblies() {
return new[] { Assembly.GetExecutingAssembly() };
}
}首先,我们重新定义了 Bootstrapper 类的 Configure 方法:这使我们能够设置我们的依赖注入容器,并执行任何其他框架配置,例如自定义约定。在这里,我们创建了一个 SimpleContainer,并向其中添加了 WindowManager、EventAggregator 和 ShellViewModel 等组件。
但是,我们没有添加 ShellView,因为我们使用了 Assembly.Source.Instance。那么,Assembly.Source.Instance 是指什么呢?这是 Caliburn.Micro 用于查找 View 的地方。您可以随时向这里添加程序集,以使它们对框架可用。在 Bootstrapper 中还有一个特殊的位置可以执行此操作,简单的重写一下 SelectAssemblies,如下所示
protected override IEnumerable<Assembly> SelectAssemblies() {
return new[] { Assembly.GetExecutingAssembly() };
}您所需做的是返回一个可搜索的程序集列表。默认情况下,基类会返回您应用程序所在的程序集。如果您的所有 View 都与应用程序位于同一个程序集中,您甚至不需要担心这一点。但是,如果您有多个引用程序集包含 View,那么这就是您需要记住的扩展点。另外,如果您要动态加载模块,就需要确保它们在加载时已经注册到 IoC 容器和 AssemblySource.Instance 中。
创建了容器并向其提供了目录后,代码添加了一些 Caliburn.Micro 特定的服务。该框架提供了 IWindowManager 和 IEventAggregator 的默认实现。
配置完成后还需要告诉 CM 我如何从 IoC 中使用这些实例,这就是接下来的三个覆盖的目的。框架需要 GetInstance、GetAllInstances、BuildUp 可选地用于向框架执行的 IResult 实例提供属性依赖项。
值得注意的事项
- 尽管 Caliburn.Micro 通过 Bootstrapper 的覆盖和 IoC 类提供了 ServiceLocator[1] 的功能,但你应该避免直接在应用程序代码中使用这个功能。许多人认为 ServiceLocator 是一种反模式。直接从容器中获取依赖关系往往会掩盖依赖代码的意图,并使测试变得更加复杂。
- Bootstrapper 还有一些其他值得注意的方法。你可以覆盖 OnStartup 和 OnExit 分别在应用程序启动或关闭时执行代码,并覆盖 OnUnhandledException 在任何未被应用程序代码专门处理的异常后清理。
BootstrapperBase 可以重写的虚方法
protected virtual void StartDesignTime():由 bootstrapper 构造函数调用,在设计时用于启动框架;protected virtual void StartRuntime():由 bootstrapper 构造函数调用,在运行时时用于启动框架;protected virtual void PrepareApplication():构建一些 hook 到 Application 对象;protected virtual void Configure():重写框架的配置以及构造使用的 IoC 容器;protected virtual IEnumerable<Assembly> SelectAssemblies():重写来告诉框架要检查程序集的位置来查找 View 等功能;protected virtual object GetInstance(Type service, string key):重写提供 IoC 容器的具体实现,该方法用于获取单个实例;protected virtual IEnumerable<object> GetAllInstances(Type service):重写提供 IoC 容器的具体实现,该方法用于获取全部实例;protected virtual void BuildUp(object instance):重写提供 IoC 容器的具体实现,方法允许你在对象实例化之后对其进行一些额外的处理,例如执行一些初始化操作,然后再注入依赖项;protected virtual void OnStartup(object sender, StartupEventArgs e):重写来执行一些自定义的行为在程序启动后;protected virtual void OnExit(object sender, EventArgs e):重写来执行一些自定义行为在程序结束时;protected virtual void OnUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e):重写来执行一些自定义行为在程序发生一些没有处理的异常时;
ServiceLocator 是一个设计模式,用于解耦应用程序中的类与其依赖的具体实现。它通常被用作 IoC(Inversion of Control,控制反转)容器的一部分,用于查找并获取特定类型的服务或依赖项。但是直接从容器中解析依赖关系会导致代码耦合性增加,并且可能会使代码难以理解和测试。 ↩︎