如何在独立类库的Caliburn.Micro ViewModel中关闭WPF应用?
解决ViewModel在独立类库中关闭WPF应用的问题
我之前也碰到过这种ViewModel和WPF项目分离的场景,确实不能直接引用System.Windows.Application,不过借助Caliburn.Micro的特性和依赖注入思想,有几种优雅的解决办法:
方案1:通过依赖注入传递关闭委托
这是最直接的方式,把关闭应用的逻辑封装成委托,从WPF项目注入到ViewModel中,ViewModel只需要调用委托即可,完全不用依赖WPF API。
- 在你的ViewModel基类
ViewModelBase中添加一个用于关闭应用的委托属性:
public abstract class ViewModelBase : PropertyChangedBase { // 其他已有属性:IoC、窗口管理器、事件聚合器... protected Action? ShutdownApp { get; set; } // 提供统一调用方法给子类ViewModel protected void RequestShutdown() { ShutdownApp?.Invoke(); } }
- 在WPF项目的Bootstrapper(比如
AppBootstrapper)中,配置依赖注入时赋值这个委托:
public class AppBootstrapper : BootstrapperBase { private SimpleContainer _container; public AppBootstrapper() { Initialize(); } protected override void Configure() { _container = new SimpleContainer(); // 注册Caliburn.Micro核心服务 _container.Singleton<IWindowManager, WindowManager>(); _container.Singleton<IEventAggregator, EventAggregator>(); // 注册ViewModel并注入关闭委托 _container.PerRequest<MainViewModel>(() => { var vm = new MainViewModel(); vm.ShutdownApp = () => System.Windows.Application.Current.Shutdown(); return vm; }); } // 其他Bootstrapper重写方法... }
- 在目标ViewModel中,需要关闭应用时直接调用:
public class MainViewModel : ViewModelBase { public void OnExitButtonClicked() { RequestShutdown(); } }
方案2:使用事件聚合器发布退出事件
这种方式更符合解耦思想,ViewModel只负责发布“需要退出”的事件,WPF项目负责订阅并执行关闭逻辑。
- 在ViewModel类库中定义一个空的事件类:
public class RequestApplicationShutdownEvent { }
- 在ViewModel中通过
IEventAggregator发布事件:
public class MainViewModel : ViewModelBase { private readonly IEventAggregator _eventAggregator; public MainViewModel(IEventAggregator eventAggregator) { _eventAggregator = eventAggregator; } public void OnExitButtonClicked() { _eventAggregator.PublishOnUIThread(new RequestApplicationShutdownEvent()); } }
- 在WPF项目的Bootstrapper中订阅并处理事件:
public class AppBootstrapper : BootstrapperBase { private IEventAggregator _eventAggregator; protected override void OnStartup(object sender, StartupEventArgs e) { _eventAggregator = IoC.Get<IEventAggregator>(); _eventAggregator.Subscribe(this); DisplayRootViewFor<MainViewModel>(); } // 处理退出事件 public void Handle(RequestApplicationShutdownEvent message) { System.Windows.Application.Current.Shutdown(); } // 其他Bootstrapper方法... }
方案3:定义抽象服务接口
通过抽象接口隔离WPF的具体实现,ViewModel只依赖接口,WPF项目提供实现。
- 在ViewModel类库中定义接口:
public interface IApplicationService { void Shutdown(); }
- 在
ViewModelBase中注入该接口:
public abstract class ViewModelBase : PropertyChangedBase { protected readonly IApplicationService _applicationService; protected ViewModelBase(IApplicationService applicationService) { _applicationService = applicationService; } protected void RequestShutdown() { _applicationService.Shutdown(); } }
- 在WPF项目中实现接口:
public class WpfApplicationService : IApplicationService { public void Shutdown() { System.Windows.Application.Current.Shutdown(); } }
- 在Bootstrapper中注册服务:
protected override void Configure() { _container = new SimpleContainer(); // 注册核心服务... _container.Singleton<IApplicationService, WpfApplicationService>(); // 注册ViewModel... }
方案4:利用Caliburn.Micro的窗口关闭约定
如果你的退出逻辑就是关闭主窗口(主窗口关闭后WPF默认退出应用),可以直接用Caliburn的约定:ViewModel中定义Close方法,绑定到按钮即可,Caliburn会自动处理窗口关闭。
public class MainViewModel : ViewModelBase { public void Close() { // 无需写逻辑,Caliburn会自动关闭当前绑定的窗口 } }
View中绑定按钮:
<Button Content="退出" cal:Message.Attach="[Event Click] = [Action Close]" />
内容的提问来源于stack exchange,提问作者ZaHaDum1984
相关产品推荐
相关产品推荐

