首页 > 解决方案 > 使用 Prism 事件聚合器从代码隐藏到视图模型进行通信

问题描述

我正在使用 MVVM 模式开发 WPF 应用程序。此外,我一直在利用 Prism 事件聚合器功能在视图模型之间进行通信。

我们正在使用一个控件库,并且我们正在使用的其中一个控件(更改/自定义的数据网格)具有库作者创建的事件。例如,当一个单元格结束编辑时......类似于丢失焦点。我面临的问题是库控件利用背后的代码而不是事件方法的视图模型。

我想我会简单地利用事件聚合器让 VM 从后面的代码中了解事件。它不工作。我的虚拟机在构造函数中使用了一个简单的订阅...

_eventAggregator.GetEvent<AfterLineAmountPaidEvent>().Subscribe(OnLineAmountPaidChanged);

OnLineAmountPaidChanged 方法永远不会受到影响。

在代码隐藏中,我正在发布事件......

_eventAggregator.GetEvent<AfterLineAmountPaidEvent>().Publish(
                    new AfterLineAmountPaidEventArgs
                    {
                        InvoiceLinesSelectedAmount = InvoiceLinesDataGrid.ItemsSource
                    });

我想知道它是否与 Prism 库和事件聚合器的实例化有关。在VM中,我通过构造函数创建它......

IEventAggregator eventAggregator

我正在使用基本 VM 扩展 VM...

: base(eventAggregator, messageDialogService)

然后,我将实例化分配给我使用的私有,如前面的代码所示......

private readonly IEventAggregator _eventAggregator;

在代码隐藏中,我按如下方式实例化事件聚合器......

private readonly IEventAggregator _eventAggregator = new EventAggregator();

当我使用断点单步执行代码时,我注意到一旦代码从 2(二)到 0(零)命中代码隐藏,订阅就会发生变化。这就是为什么我认为它正在以我使用库的方式在后面的代码中为应用程序重新实例化。

是否有不同/更好的方式来完成这种沟通?我是否错误地实例化了事件聚合器?

任何建议都是有帮助的。

标签: c#wpfprismeventaggregator

解决方案


你的猜测是正确的。问题是你有两个EventAggregator对象。您的代码不应该实例化 EventAggregator。它应该是从 Prism 给你的。您的代码隐藏需要获得与EventAggregator您的视图模型相同的实例。

好处是您可以将相同的内容注入EventAggregator到与您的视图模型一起使用的视图中,就像视图模型获取它一样。通过构造函数注入。然后从那里将它传递给任何其他代码隐藏者。

这是一个例子。我有一个名为 my 的 Prism 模块ExploreModule。在模块派生类中,我的 RegisterTypes 函数如下所示:

public void RegisterTypes(IContainerRegistry reg)
{
    reg.RegisterForNavigation<ExploreView>(ModuleKey.Explore);
}

在我的应用程序中,与我一起使用的视图模型ExploreView称为ExploreVm. 您看不到它在此处列出,因为我使用 Prism 的“视图模型定位器”方法。但基本上每当 Prism 创建 my 时ExploreView,它都会创建一个ExploreVm与之配套的。

这意味着我可以将任何我想要的注册服务添加到ExploreVmor的构造函数中ExploreView。包含IEventAggregator

所以我编辑我ExploreVmIEventAggregator. 这是我使用的那个。它还添加IEventAggregator了我个人创建和注册的另一项服务。由于 Prism 为我创建了这个视图模型,所以它只为我提供了两种服务。

public ExploreVm(ICaptureService  capSvc, IEventAggregator agg)
{
    // ...
}

ExploreView如果我愿意,我也可以用同样的方式编辑

public ExploreView(IEventAggregator aggregator)
{
    Aggregator = aggregator;
    InitializeComponent();
}

您应该有一个类似的视图/视图模型对,您可以在其中执行相同的操作。

现在,如果我有一些需要访问的子视图/控件(不是由 Prism 创建的)IEventAggregator,那么我将IEventAggregator在属性中公开它或使用其他方式将其传递下去。但是这个 Prism 创建的视图/视图模型是入口点。

无论如何,关键是您不要创建 EventAggregator。棱镜可以。


推荐阅读