确定,
这个问题适用于对PRISM有深入了解的人或者我缺乏的一些魔法技能。背景很简单:Prism允许声明用户可以订阅或发布的事件。在代码中,这看起来像这样:
_eventAggregator.GetEvent<LayoutChangedEvent>().Subscribe(UpdateUi, true);
_eventAggregator.GetEvent<LayoutChangedEvent>().Publish("Some argument");
现在这很好,特别是因为这些事件是强类型的,声明是小菜一碟:
public class LayoutChangedEvent : CompositePresentationEvent<string>
{
}
但现在遇到困难的部分:我想以某种方式追踪事件。我有想法使用lambda表达式订阅调用简单的日志消息。在WPF中工作得很好,但在Silverlight中有一些方法访问错误(花了我一些时间来弄清楚原因)..如果你想亲眼看看,请在Silverlight中尝试:
eA.GetEvent<VideoStartedEvent>().Subscribe(obj => TraceEvent(obj, "vSe", log));
如果可以,我会很高兴,因为我可以使用一行来轻松跟踪所有事件进行订阅。但它没有...替代方法是为每个事件编写不同的函数,并将此函数分配给事件。为什么功能不同?好吧,我需要知道哪个事件发布了。如果我对两个不同的事件使用相同的函数,我只将有效负载作为参数。我现在可以找出导致跟踪消息的事件。
我试过了:
还有其他想法吗? 克里斯
PS:写这篇文章花了我很可能比为20个事件编写20个函数更长,但我拒绝放弃:-)我只是想使用postharp,这很可能会工作(虽然我不是当然,也许我最终只得到有关基类的信息)..棘手且不那么重要的话题......答案 0 :(得分:5)
最简单的事情可能是继承CompositePresentationEvent并覆盖Publish事件的行为。这是CompositePresentationEvent的源代码: http://compositewpf.codeplex.com/SourceControl/changeset/view/26112#496659
以下是当前的发布行为:
public virtual void Publish(TPayload payload)
{
base.InternalPublish(payload);
}
所以你可以添加一点:
public virtual override void Publish(TPayload payload)
{
ILoggerFacade logger = ServiceLocator.Current.GetInstance<ILoggerFacade>();
logger.Log("Publishing " + payload.ToString(), Category.Debug, Priority.Low);
base.InternalPublish(payload);
}
我在这里使用Prism内置的记录器工具,但可以随意替换(或者更好,只需实现ILoggerFacade!)。
我很惊讶在这个系统中发布了任何默认消息或插入跟踪的地方......尽管EventAggregator被人们滥用,你会认为这是一个很大的要求!
答案 1 :(得分:1)
有点晚,但迟到总比没有好!我最近遇到了同样的问题,这就是我解决它的方法。
首先,我不喜欢发布/订阅事件的Prism方法,所以我使用了这样的方法: http://neverindoubtnet.blogspot.com/2009/07/simplify-prism-event-aggregator.html
上面的这篇文章建议在Event Aggregator上使用Extension方法来简化对发布/订阅的调用。因此,您的客户端代码如下所示:
IEventAggregator ev;
ev.Publish<MyCustomMessage>();
//or
ev.Publish(new MyCustomMessage(someData));
//and similarly subscription
ev.Subscribe<MyCustomMessage(this.OnCustomMessageReceived);
// ...
private void OnCustomMessageReceived(MyCustomMessage message)
{
// ...
}
// With a BaseMessageEvent class as follows (see the blog post above for where this comes from)
/// <summary>
/// Base class for all messages (events)
/// </summary>
/// <typeparam name="TMessage">The message type (payload delivered to subscribers)</typeparam>
public class BaseEventMessage<TMessage> : CompositePresentationEvent<TMessage>
{
}
好的,这很棒,但是我没有使用hacky扩展方法,而是实现了我自己的事件服务,如下所示:
/// <summary>
/// The EventService instance
/// </summary>
public class EventService : IEventService
{
private readonly IEventAggregator eventAggregator;
private readonly ILoggerFacade logger;
/// <summary>
/// Initializes a new instance of the <see cref="EventService"/> class.
/// </summary>
/// <param name="logger">The logger instance.</param>
/// <param name="eventAggregator">The event aggregator instance.</param>
public EventService(IEventAggregator eventAggregator, ILoggerFacade logger)
{
this.logger = logger;
this.eventAggregator = eventAggregator;
}
#region IEventService Members
/// <summary>
/// Publishes the event of type TMessageType to all subscribers
/// </summary>
/// <typeparam name="TMessageType">The message type (Payload), must inherit CompositeEvent</typeparam>
public void Publish<TMessageType>() where TMessageType : BaseEventMessage<TMessageType>, new()
{
TMessageType message = Activator.CreateInstance<TMessageType>();
this.Publish(message);
}
/// <summary>
/// Publishes the event of type TMessageType to all subscribers
/// </summary>
/// <typeparam name="TMessageType">The message type (Payload), must inherit CompositeEvent</typeparam>
/// <param name="message">The message to publish</param>
public void Publish<TMessageType>(TMessageType message) where TMessageType : BaseEventMessage<TMessageType>, new()
{
// Here we can log our message publications
if (this.logger != null)
{
// logger.log etc..
}
this.eventAggregator.GetEvent<TMessageType>().Publish(message);
}
/// <summary>
/// Subscribes to the event of type TMessage
/// </summary>
/// <typeparam name="TMessageType">The message type (Payload), must inherit CompositeEvent</typeparam>
/// <param name="action">The action to execute when the event is raised</param>
public void Subscribe<TMessageType>(Action<TMessageType> action) where TMessageType : BaseEventMessage<TMessageType>, new()
{
// Here we can log our message publications
if (this.logger != null)
{
// logger.log etc..
}
this.eventAggregator.GetEvent<TMessageType>().Subscribe(action);
}
#endregion
}
然后我将IEventService / EventService注册为引导程序中的单例并忘记使用IEventAggregator,只需使用它(但是如果有人使用IEventAggregator,它与EventService使用的实例相同,那么仍然可以工作)。
最后,另一个要添加的技巧是使用Stack Frame告诉我出版物和订阅的来源。请注意,这是一个缓慢的过程(展开堆栈框架),因此请谨慎使用。如果你是 定期发起一个事件然后可能在你的BaseEventMessage中放一个标志,并检查是否要记录某些事件类型的发布。
// Inside Publish method ... Log the subscription
if (this.logger != null)
{
Type messageType = typeof(TMessageType);
Type callingType = GetCallingType();
string methodName = GetCallingMethod().Name;
// Log the publication of this event
this.logger.Log(
string.Format("Event {0} was published by {1}.{2}()",
messageType.Name,
callingType.Name,
methodName),
Category.Debug,
Priority.Low));
}
// Additional methods to add to EventService to get the calling type/class
//
/// <summary>
/// Gets the Type that called the method or property where GetCallingType is called
/// </summary>
/// <returns>The class type that called</returns>
[MethodImplAttribute(MethodImplOptions.NoInlining)]
public static Type GetCallingType()
{
int skip = 2;
MethodBase method = new StackFrame(skip, false).GetMethod();
return method.DeclaringType;
}
/// <summary>
/// Gets the Method that called the method or property where GetCallingMethod is called
/// </summary>
/// <returns>The method type that was called</returns>
public static MethodBase GetCallingMethod()
{
return new StackFrame(2, false).GetMethod();
}
注意上面的内容在Silverlight(StackFrame的使用)中不起作用,但其余的确如此。在调试Prism app周围的大量事件时,我发现这非常宝贵!