You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在HomeViewModel中调用MainViewModel的TestEvent方法?Prism使用报错

问题描述

我有HomeViewModel和MainViewModel,想要在HomeViewModel中调用MainViewModel的TestEvent方法,尝试使用Prism框架的IEventAggregator实现,但在MainViewModel构造函数中传入IEventAggregator参数时,持续出现以下错误:

Exception thrown: 'System.MissingMethodException' in System.Xaml.dll
Exception thrown: 'System.Xaml.XamlObjectWriterException' in System.Xaml.dll
Exception thrown: 'System.NullReferenceException' in System.Private.CoreLib.dll
Object reference not set to an instance of an object.

同时,若在HomeViewModel构造函数中传入IEventAggregator也会出现类似错误。

MainViewModel代码

using Learning.Core;
using Learning.EventRegister;
using Learning.MVVM.Model;
using Prism.Events;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace Learning.MVVM.ViewModel
{
    public class MainViewModel: ObservableObject
    {
        public RelayCommand HomeViewConmmand { get; set; }
        public RelayCommand DiscoveryViewConmmand { get; set; }
        public RelayCommand TestCommand { get; set; }

        public HomeViewModel HomeVM { get; set; }
        public DiscoveryViewModel DiscoveryVM { get; set; }
        public RoomViewModel RoomVM { get; set; }

        private object _currentView;
        private object _rightView;

        IEventAggregator _eventAggregator;

        public object CurrentView
        {
            get { return _currentView; }
            set { 
                _currentView = value;
                OnPropertyChanged();
            }
        }

        public object RightView
        {
            get { return _rightView; }
            set
            {
                _rightView = value;
                OnPropertyChanged();
            }
        }

        public MainViewModel(IEventAggregator ea) {
            HomeVM = new HomeViewModel();
            DiscoveryVM = new DiscoveryViewModel();
            RoomVM = new RoomViewModel();
            CurrentView = HomeVM;
            RightView = RoomVM;

            HomeViewConmmand = new RelayCommand(o =>
            {
                CurrentView = HomeVM;
            });

            DiscoveryViewConmmand = new RelayCommand(o =>
            {
                CurrentView = DiscoveryVM;
            });

            TestCommand = new RelayCommand(o =>
            {
                MessageBox.Show("Clicked");
            });
        }

        public void TestEvent(string message)
        {
            MessageBox.Show(message);
        }
    }
}

HomeViewModel代码

using Learning.Core;
using Learning.EventRegister;
using Learning.MVVM.Model;
using Prism.Events;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace Learning.MVVM.ViewModel
{
    public class HomeViewModel
    {
        // Data
        public List<Room> rooms { get; }

        // Command
        private RelayCommand openRoomCommand;

        //IEventAggregator 
        IEventAggregator _eventAggregator;

        public RelayCommand NotifyCommand { get; set; }

        public HomeViewModel()
        {
            openRoomCommand = new RelayCommand(o =>
            {
                Room cur_room = (Room)o;
                cur_room.IsActive = true;
            });

            rooms = new List<Room>();
            Room room1 = new Room
            {
                Name = "1",
                IsActive = false,
            };
            Room room2 = new Room
            {
                Name = "2",
                IsActive = false,
            };
            Room room3 = new Room
            {
                Name = "3",
                IsActive = false,
            };
            Room room4 = new Room
            {
                Name = "4",
                IsActive = false,
            };

            rooms.Add(room1);
            rooms.Add(room2);
            rooms.Add(room3);
            rooms.Add(room4);
        }

        public void SendEvent()
        {
            //_eventAggregator.GetEvent<CommandSendEvent>().Publish("Something happening");
        }

        public RelayCommand OpenRoomCommand { get => openRoomCommand; }
    }
}
解决方案

1. 解决构造函数注入错误

报错核心原因:

  • 手动new ViewModel实例(如HomeVM = new HomeViewModel()),未通过Prism依赖注入容器创建,导致IEventAggregator无法自动注入。
  • 若XAML中直接实例化MainViewModel,会尝试调用无参构造函数,但你只定义了带IEventAggregator参数的构造函数,因此抛出MissingMethodException。

修复步骤:

  • 确保项目使用Prism依赖注入容器(如Unity、DryIoc),Prism默认已注册IEventAggregator。
  • 不要手动new ViewModel,改为通过容器解析:
    public MainViewModel(IEventAggregator ea, HomeViewModel homeVM, DiscoveryViewModel discoveryVM, RoomViewModel roomVM) 
    {
        _eventAggregator = ea;
        HomeVM = homeVM;
        DiscoveryVM = discoveryVM;
        RoomVM = roomVM;
        // 其他初始化代码...
    }
    
  • 或启用Prism的ViewModelLocator,让View自动关联ViewModel,无需手动实例化。

2. 用Prism EventAggregator实现跨ViewModel通信

步骤1:定义事件类

创建继承自PubSubEvent<string>的事件类,用于传递消息:

using Prism.Events;

namespace Learning.EventRegister
{
    public class CommandSendEvent : PubSubEvent<string>
    {
    }
}

步骤2:在MainViewModel中订阅事件

在MainViewModel构造函数中订阅事件,关联到TestEvent方法:

public MainViewModel(IEventAggregator ea, HomeViewModel homeVM, DiscoveryViewModel discoveryVM, RoomViewModel roomVM) 
{
    _eventAggregator = ea;
    // 订阅事件,事件发布时调用TestEvent
    _eventAggregator.GetEvent<CommandSendEvent>().Subscribe(TestEvent);
    
    HomeVM = homeVM;
    DiscoveryVM = discoveryVM;
    RoomVM = roomVM;
    // 其他初始化代码...
}

步骤3:在HomeViewModel中注入IEventAggregator并发布事件

修改HomeViewModel构造函数,注入IEventAggregator并完善SendEvent方法:

public class HomeViewModel
{
    // ... 其他成员 ...
    
    IEventAggregator _eventAggregator;

    // 修改构造函数,注入IEventAggregator
    public HomeViewModel(IEventAggregator eventAggregator)
    {
        _eventAggregator = eventAggregator;
        
        // 其他初始化代码...
        
        // 给NotifyCommand赋值,触发SendEvent
        NotifyCommand = new RelayCommand(o => SendEvent());
    }

    public void SendEvent()
    {
        _eventAggregator.GetEvent<CommandSendEvent>().Publish("Something happening");
    }

    // ... 其他成员 ...
}

步骤4:确保ViewModel通过容器解析

在Prism容器注册代码中(如App.xaml.cs的RegisterTypes方法),注册所有ViewModel:

protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
    containerRegistry.Register<HomeViewModel>();
    containerRegistry.Register<DiscoveryViewModel>();
    containerRegistry.Register<RoomViewModel>();
    containerRegistry.Register<MainViewModel>();
}

容器创建MainViewModel和HomeViewModel时,会自动注入同一个IEventAggregator实例,HomeViewModel发布事件后,MainViewModel的TestEvent方法会被调用。


内容的提问来源于stack exchange,提问作者Văn Hào Trương

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 17:27:54