在Prism中,有一个重要的功能,就是事件聚合器,也就是消息机制,是大家常用的功能。主要是为了实现不同模块之间的信息交互。在prism的官方demo中也给出了简单的使用例子。但是在实际使用过程中,模块多了,消息多了,会非常的难调试,因此我这里对消息机制做了一次封装,并且统一去管理定义各个模块用到的消息。代码比较简单,我这里只是对官方的例子做了一个改造,大家可以参考一下。红色为主要改动的部分,代码结构如下图:
主要代码如下:
SendMessageMsg.cs
namespace UsingEventAggregator.Core.Messages
{
public class SendMessageMsg
{
public string SendMessage { get; set; }
}
}
FrameMessenger.cs
using Prism.Events;
using Prism.Ioc;
using System;
namespace UsingEventAggregator.Core
{
public class FrameMessenger
{
private static readonly FrameMessenger _instance = new FrameMessenger();
private readonly IEventAggregator _eventAggregator;
public static FrameMessenger Instance
{
get { return _instance; }
}
private FrameMessenger()
{
_eventAggregator = (IEventAggregator)ContainerLocator.Container.Resolve(typeof(IEventAggregator));
}
/// <summary>
/// 发布方法
/// </summary>
/// <typeparam name="T">泛型</typeparam>
/// <param name="t">T类型消息</param>
public void Publish<T>(T t)
{
_eventAggregator.GetEvent<PubSubEvent<T>>().Publish(t);
}
/// <summary>
/// 订阅T类型消息
/// </summary>
/// <typeparam name="T">泛型</typeparam>
/// <param name="action">订阅方法,用于执行接受消息的动作</param>
public void Subscribe<T>(Action<T> action)
{
_ = _eventAggregator.GetEvent<PubSubEvent<T>>().Subscribe(action);
}
/// <summary>
/// 订阅T类型消息,且增加过滤条件
/// </summary>
/// <typeparam name="T">泛型</typeparam>
/// <param name="action">订阅方法,用于执行接受消息的动作</param>
/// <param name="filter">过滤条件</param>
public void Subscribe<T>(Action<T> action, Predicate<T> filter)
{
_ = _eventAggregator.GetEvent<PubSubEvent<T>>().Subscribe(action, filter);
}
/// <summary>
/// 订阅T类型消息,且增加过滤条件,是否同步执行,保持强引用
/// </summary>
/// <typeparam name="T">泛型</typeparam>
/// <param name="action">订阅方法,用于执行接受消息的动作</param>
/// <param name="filter">过滤条件</param>
/// <param name="sync">是否同步</param>
/// <param name="keepSubscriberReferenceAlive">是否保持强引用</param>
public void Subscribe<T>(Action<T> action, Predicate<T> filter = null, bool sync = false, bool keepSubscriberReferenceAlive = false)
{
_ = _eventAggregator.GetEvent<PubSubEvent<T>>().Subscribe(action,
sync ? ThreadOption.PublisherThread : ThreadOption.BackgroundThread,
keepSubscriberReferenceAlive,
filter);
}
/// <summary>
/// 取消订阅
/// </summary>
/// <typeparam name="T">泛型</typeparam>
/// <param name="action">订阅方法</param>
public void Unsubscribe<T>(Action<T> action)
{
_eventAggregator.GetEvent<PubSubEvent<T>>().Unsubscribe(action);
}
}
}
MainWindowViewModel.cs
using Prism.Mvvm;
namespace UsingEventAggregator.ViewModels
{
public class MainWindowViewModel : BindableBase
{
private string _title = "Prism Unity Application";
public string Title
{
get { return _title; }
set { SetProperty(ref _title, value); }
}
public MainWindowViewModel()
{
}
}
}
MainWindow.xaml
<Window x:Class="UsingEventAggregator.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
Title="{Binding Title}" Height="350" Width="525">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ContentControl prism:RegionManager.RegionName="LeftRegion" />
<ContentControl Grid.Column="1" prism:RegionManager.RegionName="RightRegion" />
</Grid>
</Window>
MessageViewModel.cs
using Prism.Commands;
using Prism.Mvvm;
using UsingEventAggregator.Core;
using UsingEventAggregator.Core.Messages;
namespace ModuleA.ViewModels
{
public class MessageViewModel : BindableBase
{
private string _message = "Message to Send";
public string Message
{
get { return _message; }
set { SetProperty(ref _message, value); }
}
public DelegateCommand SendMessageCommand { get; private set; }
public MessageViewModel()
{
SendMessageCommand = new DelegateCommand(SendMessage);
}
private void SendMessage()
{
FrameMessenger.Instance.Publish<SendMessageMsg>(new SendMessageMsg {SendMessage= Message });
}
}
}
MessageView.xaml
<UserControl x:Class="ModuleA.Views.MessageView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True" Padding="25">
<StackPanel>
<TextBox Text="{Binding Message}" Margin="5"/>
<Button Command="{Binding SendMessageCommand}" Content="Send Message" Margin="5"/>
</StackPanel>
</UserControl>
ModuleAModule.cs
using ModuleA.Views;
using Prism.Ioc;
using Prism.Modularity;
using Prism.Regions;
namespace ModuleA
{
public class ModuleAModule : IModule
{
public void OnInitialized(IContainerProvider containerProvider)
{
var regionManager = containerProvider.Resolve<IRegionManager>();
regionManager.RegisterViewWithRegion("LeftRegion", typeof(MessageView));
}
public void RegisterTypes(IContainerRegistry containerRegistry)
{
}
}
}
MessageListViewModel.cs
using Prism.Events;
using Prism.Mvvm;
using System.Collections.ObjectModel;
using UsingEventAggregator.Core;
using UsingEventAggregator.Core.Messages;
namespace ModuleB.ViewModels
{
public class MessageListViewModel : BindableBase
{
private ObservableCollection<string> _messages;
public ObservableCollection<string> Messages
{
get { return _messages; }
set { SetProperty(ref _messages, value); }
}
public MessageListViewModel()
{
Messages = new ObservableCollection<string>();
FrameMessenger.Instance.Subscribe<SendMessageMsg>(MessageReceived);
}
private void MessageReceived(SendMessageMsg message)
{
Messages.Add(message.SendMessage);
}
}
}
MessageList.xaml
<UserControl x:Class="ModuleB.Views.MessageList"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True" Padding="25">
<Grid>
<ListBox ItemsSource="{Binding Messages}" />
</Grid>
</UserControl>
ModuleBModule.cs
using ModuleB.Views;
using Prism.Ioc;
using Prism.Modularity;
using Prism.Regions;
namespace ModuleB
{
public class ModuleBModule : IModule
{
public void OnInitialized(IContainerProvider containerProvider)
{
var regionManager = containerProvider.Resolve<IRegionManager>();
regionManager.RegisterViewWithRegion("RightRegion", typeof(MessageList));
}
public void RegisterTypes(IContainerRegistry containerRegistry)
{
}
}
}