今天 说一下Caliburn.Micro的IEventAggregator和IHandle<T>分成两篇去讲这一篇写一个简单的例子
看一它的的实现和源码
下一篇用它们做一个多语言的demo
这两个是事件的订阅和广播,很强大,但用的时候要小心发生不必要的冲突。
先看一下它的实现思想
在Caliburn.Micro里EventAggregator要以单例的形式出现这样可以做到对广播做到统一的管理
对象实现IHand<T>接口后通过EventAggregator的subsribe方法把自己加入到Handler集合中这样就能接叫信息
能过EventAggregator.Publish(object obj)方法去发送广播
先看一下个小demo再去分析它的源码是怎么实现的
先写一个消息类,这个类只是做一个IHandle<T>的类型应用没有什么实际意义
class MyMessage { public string Str { get; set; } override string ToString() { return Str; } }
建一个窗体MainView和一个viewmodel类
<Window x:Class="CaliburnIHandle.MyViews.MyMainView" xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml" Title=MyMainView" Height=300" Width="> <StackPanel> <TextBox x:Name=StrMessage" Margin=5"/> <Button x:Name=OpenOneWin" Content="/> <Button Content=Publish" x:Name="/> </StackPanel> </Window>
窗体有一个textBox显示消息。一个button打开窗体一个发布消息
再看一下viewmodel
实现 了两个IHandle<T> 一个是string 类型一个是我们自己定义的MyMessage
Mainviewmode发布string类型的广播也接收string类型和MyMessage类型的消息
[Export(typeof(IShell))] class MyMainviewmodel : PropertyChangedBase,IHandle<string>,IHandle<MyMessage> { readonly IEventAggregator _events; readonly IWindowManager _windowManager; string strMessage; string StrMessage { get { return strMessage; } set { strMessage = value; NotifyOfPropertyChange(() => StrMessage); } } [ImportingConstructor] public MyMainviewmodel(IEventAggregator e,IWindowManager win) { _events = e; _events.Subscribe(this); _windowManager = win; } void Handle(string message) { StrMessage = message; } void Handle(MyMessage message) { StrMessage = message.ToString(); } #region void Publish() { _events.Publish(StrMessage); } #endregion #region 打开窗体 void OpenOneWin() { OneCviewmodel _one=new OneCviewmodel(); _windowManager.ShowWindow(_one); } #endregion
再建一个窗体做接收和广播
它只接收string类型的消息和发布MyMessage类型的消息
<UserControl x:Class=CaliburnIHandle.MyViews.OneCView" xmlns=" xmlns:x=" xmlns:mc=http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d=http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable=d" Height="> <StackPanel> <TextBlock FontSize=13" HorizontalAlignment=Center">1</TextBlock> <TextBox Margin=OneMessage"></TextBox> <Button Margin=OnePublish"/> </StackPanel> </UserControl>
using Caliburn.Micro; using CaliburnIHandle.CommonC; using System; using System.Collections.Generic; using System.ComponentModel.Composition; using System.Linq; using System.Text; namespace CaliburnIHandle.Myviewmodels { [Export(typeof(OneCviewmodel))] class OneCviewmodel : PropertyChangedBase,255); line-height:1.5!important">string> { readonly IEventAggregator _event; string oneMessage; string OneMessage { return oneMessage; } set { oneMessage = value; NotifyOfPropertyChange(() => OneMessage); } } public OneCviewmodel() { _event = IoC.Get<IEventAggregator>(); _event.Subscribe(this); } void OnePublish() { _event.Publish(new MyMessage { Str = OneMessage + One!" }); } string message) { OneMessage = message; } } }
这是一个很简单的例子我们看一下Caliburn.Micro源码它是怎么实现的
看一下IHandle<T>接口
interface IHandle<TMessage> : IHandle { //don't use contravariance here /// <summary> /// Handles the message. </summary> <param name = "message">The message.</param> void Handle(TMessage message); }
IHandle<T>只有一个处理T事件的的方法
EventAggregator类通过
Subscribes an instance to all events declared through implementations of <see cref = "IHandle{T}" /> <param name = "subscriber">The instance to subscribe for event publication.virtual void Subscribe(object subscriber) { if (subscriber == null) { throw new ArgumentNullException(subscriber"); } lock(handlers) { if (handlers.Any(x => x.Matches(subscriber))) { return; } handlers.Add(new Handler(subscriber)); } }
把订阅的类放到Handlers集合里
再通过Publish发布相应的消息
Publishes a message. The message instance.</param> <remarks> Does not marshall the the publication to any special thread by default. </remarks> void Publish(object message) { if (message == message"); } Publish(message,PublicationThreadMarshaller); } <param name = "marshal">Allows the publisher to provide a custom thread marshaller for the message publication.object message,Action<System.Action> marshal) { null){ if (marshal == marshal"); } Handler[] toNotify; lock (handlers) { toNotify = handlers.ToArray(); } marshal(() => { var messageType = message.GetType(); var dead = toNotify .Where(handler => !handler.Handle(messageType,message)) .ToList(); if(dead.Any()) { lock(handlers) { dead.Apply(x => handlers.Remove(x)); } } }); }