具有多个视图的Caliburn事件聚合器
本文关键字:事件 Caliburn 视图 | 更新日期: 2023-09-27 17:50:54
我试图第一次使用Caliburn构建这个项目(也是MEF结构,我没有完全理解)。
我需要使用导体和EventAggregator。导体,因为我有一个AppViewModel"显示"3个按钮,将用户移动到3个不同的视图(AppView内的UserControls)。
我需要EventAggregator,因为这3个视图中的一个有一个按钮里面必须加载第4个视图(这必须是一个窗口,我认为,而不是一个UserControl,因为它必须是全屏)。所以我认为,当用户点击这个按钮在3视图(AppView中的UserControl)一个消息可以发送到监听器(应该是AppViewModel),这一个应该ActivateItem(第4 vm)。
我不知道为什么,但即使遵循Caliburn项目的例子,我的消息也没有到达AppViewModel。
这是我的bootstrapper:
public class AppBootstrapper : Bootstrapper<AppViewModel>
{
private CompositionContainer container;
protected override void Configure()
{
container = new CompositionContainer(new AggregateCatalog(AssemblySource.Instance.Select(x =>
new AssemblyCatalog(x)).OfType<ComposablePartCatalog>()));
CompositionBatch batch = new CompositionBatch();
batch.AddExportedValue<IWindowManager>(new WindowManager());
batch.AddExportedValue<IEventAggregator>(new EventAggregator());
batch.AddExportedValue(container);
container.Compose(batch);
}
protected override object GetInstance(Type serviceType, string key)
{
string contract = string.IsNullOrEmpty(key) ? AttributedModelServices.GetContractName(serviceType) : key;
var exports = container.GetExportedValues<object>(contract);
if (exports.Any())
return exports.First();
throw new Exception(string.Format("Could not locate any instances of contract {0}.", contract));
}
protected override IEnumerable<object> GetAllInstances(Type serviceType)
{
return container.GetExportedValues<object>(AttributedModelServices.GetContractName(serviceType));
}
protected override void BuildUp(object instance)
{
container.SatisfyImportsOnce(instance);
}
protected override void OnStartup(object sender, StartupEventArgs e)
{
DisplayRootViewFor<AppViewModel>();
}
}
AppViewModel:
[Export (typeof(AppViewModel))]
public class AppViewModel : Conductor<object>, IHandle<ChangeViewEvent>
{
[ImportingConstructor]
public AppViewModel(IEventAggregator events)
{
events.Subscribe(this);
ActivateItem(new MainViewModel());
}
public void GoToPatientsManager()
{
ActivateItem(new PatientsManagerViewModel(new WindowManager(), new EventAggregator()));
}
public void GoToTestManager()
{
ActivateItem(new TestManagerViewModel(new WindowManager()));
}
public void GoToResultsManager()
{
ActivateItem(new MainViewModel());
}
public void Handle(ChangeViewEvent message)
{
switch (message.ViewName)
{
case "TestManager" :
GoToTestManager();
break;
}
}
}
这个视图模型应该启动加载第4个vm的请求
[Export(typeof(PatientsManagerViewModel))]
public class PatientsManagerViewModel : Screen
{
private readonly IWindowManager _windowManager;
private readonly IEventAggregator eventAggregator;
[ImportingConstructor]
public PatientsManagerViewModel(IWindowManager windowManager, IEventAggregator eventAggregator)
{
_windowManager = windowManager;
this.eventAggregator = eventAggregator;
}
#region Methods
public void ShowFakeMessage()
{
dynamic settings = new ExpandoObject();
settings.Placement = PlacementMode.Center;
settings.PlacementTarget = GetView(null);
var res = _windowManager.ShowDialog(new DeletePersonViewModel(), null, settings);
if (res)
{
// The result of the dialog men. In this true case we'll use Linq to delete the entry from the database
// using the dbContext
}
}
public void GoToTestManager()
{
eventAggregator.Publish(new ChangeViewEvent("TestManager"));
}
#endregion
}
没有到达AppViewModel的Handle方法
这些是错误的视图模型的实例?我无法从这里继续前进…
编辑可以是,问题是,我通过一个新的EventAggregator对象,每次我激活一个新的PatientsManagerViewModel?任何建议吗?
你自己诊断了问题。您正在自己创建PatientsManagerViewModel,并每次传入一个新的事件聚合器。其思想是,事件聚合器必须是单例的,即在所有视图模型和其他所有事物之间共享一个实例。这是因为事件聚合器将订阅者存储在内存中,新实例不知道该通知谁新事件,因为没有人订阅过。
我建议你的AppViewModel.GoToPatientsManager()
应该看起来像这样:
public void GoToPatientsManager()
{
var patientManagerViewModel = IoC.Get<PatientsManagerViewModel>();
ActivateItem(patientManagerViewModel);
}
IoC是一种访问容器的方式(相当难看,难以测试)。你不应该自己创建视图模型,你应该让caliburn容器为你做这些。如果容器创建了您的视图模型,那么它也会为您修复任何依赖关系,包括窗口管理器和事件聚合器。