如何在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. 解决构造函数注入错误
报错核心原因:
- 手动
newViewModel实例(如HomeVM = new HomeViewModel()),未通过Prism依赖注入容器创建,导致IEventAggregator无法自动注入。 - 若XAML中直接实例化
MainViewModel,会尝试调用无参构造函数,但你只定义了带IEventAggregator参数的构造函数,因此抛出MissingMethodException。
修复步骤:
- 确保项目使用Prism依赖注入容器(如Unity、DryIoc),Prism默认已注册
IEventAggregator。 - 不要手动
newViewModel,改为通过容器解析: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
相关产品推荐
相关产品推荐

