我在视图模型中订阅了一个事件。事件订阅在视图模型的构造函数中完成,该构造函数通过unity创建。
我发现如果我订阅:
showViewAEvent.Subscribe(ShowViewAHasBeenRequested)或showViewAEvent.Subscribe(ShowViewAHasBeenRequested,False)我收到以下错误:
// {System.MethodAccessException: ModuleA.Views.ModuleAViewModel.ShowViewAHasBeenRequested(Boolean)
//at System.Delegate.BindToMethodInfo(Object target, RuntimeMethodHandle method, RuntimeTypeHandle methodType, DelegateBindingFlags flags)
//at System.Delegate.CreateDelegate(Type type, Object firstArgument, MethodInfo method, Boolean throwOnBindFailure)
//at System.Delegate.CreateDelegate(Type type, Object firstArgument, MethodInfo method)
//at Microsoft.Practices.Composite.Events.DelegateReference.TryGetDelegate()
//at Microsoft.Practices.Composite.Events.DelegateReference.get_Target()
//at Microsoft.Practices.Composite.Events.EventSubscription`1..ctor(IDelegateReference actionReference, IDelegateReference filterReference)
//at Microsoft.Practices.Composite.Presentation.Events.CompositePresentationEvent`1.Subscribe(Action`1 action, ThreadOption threadOption, Boolean keepSubscriberReferenceAlive, Predicate`1 filter)
//at Microsoft.Practices.Composite.Presentation.Events.CompositePresentationEvent`1.Subscribe(Action`1 action, ThreadOption threadOption, Boolean keepSubscriberReferenceAlive)
//at Microsoft.Practices.Composite.Presentation.Events.CompositePresentationEvent`1.Subscribe(Action`1 action, Boolean keepSubscriberReferenceAlive)
//at ModuleA.Views.ModuleAViewModel..ctor(IEventAggregator eventAggregator, IRegionManager regionManager)
//at BuildUp_ModuleA.Views.ModuleAViewModel(IBuilderContext )
//at Microsoft.Practices.ObjectBuilder2.DynamicMethodBuildPlan.BuildUp(IBuilderContext context)
//at Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy.PreBuildUp(IBuilderContext context)
//at Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context)}
但是,如果我在事件订阅时将标志设置为true,则不会收到错误。
由于我是棱镜新手,如果我在正确的位置创建订阅,我仍在努力解决。
JD。
答案 0 :(得分:4)
这是一个众所周知的问题:
http://compositewpf.codeplex.com/WorkItem/View.aspx?WorkItemId=4925
CompositePresentationEvent中的错误<> .Subscribe()会阻止弱事件引用标题是必需的
描述描述是必需的 概述:
此类的Subscribe()方法记录为默认创建WeakReferences或在包含该参数的重载中指定为keepSubscriberReferenceAlive = false。
详情:
仅在提供过滤器委托时才能正确观察到此行为。在所有其他情况下(以及Subscribe()方法的所有重载),都会创建一个强引用 - 无论记录的默认值如何,也不管keepSubscriberReferenceAlive参数的任何提供值。
此错误的来源可以在此方法的以下重载中找到:
CompositePresentationEvent.Subscribe(Action action,ThreadOption threadOption,bool keepSubscriberReferenceAlive,Predicate filter)
在此方法中,检查“过滤器”参数。如果过滤器不为null,则处理继续正确。但是,如果此参数为null,则会创建一个新的传递委托(始终返回true)并将其用于过滤器。错误是从此传递委托创建的DelegateReference对象将keepReferenceAlive参数硬编码为值“true”。此值不应该是硬编码的,而应传递传入参数keepSubscriberReferenceAlive。
替代方法:
此问题有一个简单的解决方法。注册订阅时,应始终使用上述详细过载,并始终提供过滤器委托。永远不要为filter参数传递“null”。如果不应过滤订阅,则在需要弱事件引用时应使用传递过滤器委托(典型情况):
EventAggregator.GetEvent()。订阅(MyHandler,ThreadOption.PublisherThread,false,(dummy)=> true);
以下缩写重载没有解决方法,在修补基础错误之前不应使用这些重载:
CompositePresentationEvent.Subscribe(动作动作) CompositePresentationEvent.Subscribe(Action action,ThreadOption threadOption) CompositePresentationEvent.Subscribe(动作动作,bool keepSubscriberReferenceAlive) CompositePresentationEvent.Subscribe(Action action,ThreadOption threadOption,bool keepSubscriberReferenceAlive)
答案 1 :(得分:1)
经过进一步研究,我找到了这个帖子: http://compositewpf.codeplex.com/Thread/View.aspx?ThreadId=57362
我没有意识到订阅电话实际上是在CallStack中,或者我之前会意识到这一点。这是一段摘录:
Silverlight不支持弱 对lambda表达式的引用或 匿名代表。因此, filter参数必须是单独的 如果您是定位方法 的Silverlight。
您是否尝试使用lambda作为该订阅的处理程序?如果是这样,看起来您需要做的就是使用真实的方法。
EventService.GetEvent<GenericEvent<string>>().Subscribe(YourAction) ..... public void YourAction(string topic) { if(topic == "something") { // more code } }
答案 2 :(得分:1)
ShowViewAHasBeenRequested
方法是公开的吗?如果没有,调用代码将无法访问它。
答案 3 :(得分:0)
发布事件时,您的ViewModel是否超出了范围?在Subscribe方法中传递True会创建一个强引用,这会使订阅者在超出范围后不会获得GC。了解这样做会造成内存泄漏,因为您实例化的每个ViewModel都将继续存在并响应那些已发布的事件。
在我的Module的Initialize方法中设置一些事件订阅时遇到了同样的问题 - 据我所知,在完成所有设置之后,没有任何东西正在保存对我的模块的引用。
答案 4 :(得分:0)
我有完全相同的问题并通过根据用户188067和Konamiman的响应公开过滤方法和操作方法来解决它。即。
showViewAEvent.Subscribe(ShowViewAHasBeenRequested, ThreadOption.UIThread, false, ShouldHandleEvent);
public bool ShouldHandleError(object obj)
{
return true;
}
public void ShowViewAHasBeenRequested(object obj)
{
...
}