C# 具有多个视图的Caliburn事件聚合器

C# 具有多个视图的Caliburn事件聚合器,c#,wpf,caliburn,C#,Wpf,Caliburn,我第一次尝试使用Caliburn构建这个项目(还有MEF结构,我没有完全理解) 我需要同时使用指挥器和事件聚合器。 这是因为我有一个AppViewModel,它“显示”3个按钮,将用户移动到3个不同的视图(AppView中的用户控件) 我需要EventAggregator,因为这3个视图中有一个里面有一个按钮,它必须加载第4个视图(我认为这必须是一个窗口,而不是用户控件,因为它必须是全屏的)。 因此,我认为当用户在3视图(AppView中的UserControl)中单击此按钮时,可以将消息发送到

我第一次尝试使用Caliburn构建这个项目(还有MEF结构,我没有完全理解)

我需要同时使用指挥器和事件聚合器。 这是因为我有一个AppViewModel,它“显示”3个按钮,将用户移动到3个不同的视图(AppView中的用户控件)

我需要EventAggregator,因为这3个视图中有一个里面有一个按钮,它必须加载第4个视图(我认为这必须是一个窗口,而不是用户控件,因为它必须是全屏的)。 因此,我认为当用户在3视图(AppView中的UserControl)中单击此按钮时,可以将消息发送到侦听器的顶部(这应该是AppViewModel),并且此消息应该激活Item(第四个vm)

我不知道为什么,但即使遵循Caliburn项目的示例,我的消息也没有到达AppViewModel

这是我的引导程序:

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的句柄方法

视图模型的实例是否有问题?我不能从这里继续前进

编辑


问题是否在于每次激活新PatientsManagerViewModel时都会传递一个新的EventAggregator对象?有什么建议吗?

你诊断出了自己的问题。您正在自己创建PatientsManagerViewModel,并每次传入一个新的事件聚合器。其思想是,事件聚合器必须是一个在所有视图模型和所有其他对象之间共享的单一实例。这是因为事件聚合器将订阅服务器存储在内存中,而新实例将不知道通知谁新事件,因为没有人订阅

我建议您的
AppViewModel.GoToPatientsManager()
应该如下所示:

public void GoToPatientsManager()
{
    var patientManagerViewModel = IoC.Get<PatientsManagerViewModel>();
    ActivateItem(patientManagerViewModel);
}
public void GoToPatientsManager()
{
var patientManagerViewModel=IoC.Get();
ActivateItem(患者管理者模型);
}
IoC是一种(相当难看,难以测试)访问容器的方式。您不应该自己创建视图模型,而应该让caliburn容器为您创建视图模型。如果容器创建了您的视图模型,那么它也将修复它为您提供的任何依赖项,包括窗口管理器和事件聚合器

 [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
    }
public void GoToPatientsManager()
{
    var patientManagerViewModel = IoC.Get<PatientsManagerViewModel>();
    ActivateItem(patientManagerViewModel);
}