繁体   English   中英

使用 Prism 事件聚合器从背后的代码到视图模型进行通信

[英]Use Prism Event Aggregator to Communicate from Code Behind to View Model

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

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

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

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

OnLineAmountPaidChanged 方法永远不会被命中。

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

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

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

IEventAggregator eventAggregator

我正在使用基本虚拟机扩展虚拟机...

: base(eventAggregator, messageDialogService)

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

private readonly IEventAggregator _eventAggregator;

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

private readonly IEventAggregator _eventAggregator = new EventAggregator();

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

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

任何建议都是有帮助的。

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

好消息是,您可以将相同的EventAggregator注入到与您的视图模型一起使用的视图中,就像视图模型获取它的方式一样。 通过构造函数注入。 然后将它传递给任何其他代码隐藏程序。

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

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

在我的应用程序中,与我的ExploreView一起使用的视图模型称为ExploreVm 您没有看到它在此处列出,因为我使用 Prism 的“视图-模型-定位器”方法。 但基本上,无论何时 Prism 创建我的ExploreView ,它都会创建一个ExploreVm来配合它。

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

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

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

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

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

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

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

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

@乔...

我想发表评论,以便我可以展示更多代码,您可能会指出我哪里出错了。

我的 VM 是使用 VM 工厂类创建的。 这是一个片段...

public IReceiptDetailViewModel CreateReceiptDetailViewModel(
            int? customerId,
            Action<Guid> onTabClosed,
            Action onReloadCustomerInvoicesRequested)
        {
            IReceiptDetailViewModel viewModel = new ReceiptDetailViewModel(
                customerId,
                _mapper,
                _customerDataProvider,
                _invoiceDataProvider,
                _receiptDataProvider,
                this,
                _eventAggregator,
                _messageDialogService,
                onTabClosed,
                onReloadCustomerInvoicesRequested,
                _windowService);

            return viewModel;
        }

使用传递给我的 ConfigureServices 方法的 IServiceCollection 接口从我的 App.xaml.cs 引用 VM 工厂代码。

services.AddTransient<IViewModelFactory, ViewModelFactory>();

我的应用程序构造函数如下...

   ConfigureServices(serviceCollection);
   _serviceProvider = serviceCollection.BuildServiceProvider();

我还在那里添加了一个事件聚合器的单例......

services.AddSingleton<IEventAggregator, EventAggregator>();

所以我接线错误吗? 我应该以不同的方式做吗?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM