2009-10-28 29 views
2

我有一個我在View模型中訂閱的事件。事件訂閱是在通過統一創建的視圖模型的構造函數中完成的。使用棱鏡給予方法訪問異常的事件訂閱

我發現什麼,如果我的訂閱:

showViewAEvent.Subscribe(ShowViewAHasBeenRequested)或showViewAEvent.Subscribe(ShowViewAHasBeenRequested,假)我得到以下錯誤:

 // {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,我沒有得到錯誤。

由於我是棱鏡新手,如果我在正確的位置創建訂閱,我仍然試圖解決這個問題。 JDD。

JD。

+0

我在堆棧跟蹤中找到訂閱方法後編輯了我的答案。我之前的回答假設你的應用程序稍後發生了一些事情。 –

+0

請顯示您致電Subscribe的完整代碼,以及您通過的方法。 –

回答

4

這是一個已知的問題完全記錄在這裏:

http://compositewpf.codeplex.com/WorkItem/View.aspx?WorkItemId=4925

的Bug CompositePresentationEvent <> .Subscribe()防止弱事件引用標題需要

需要

描述描述 概述:

這個類的訂閱()方法被記錄爲默認創建在WeakReferences或者當指定爲keepSubs criberReferenceAlive = false在包含該參數的重載中。

詳情:

此行爲當提供濾波器代表僅正確地觀察到。在所有其他情況下(以及Subscribe()方法的所有重載),都會創建一個強引用 - 不管文檔中的默認值如何,也不管keepSubscriberReferenceAlive參數提供的值是多少。

此錯誤的來源可以在該方法的以下過載找到:

CompositePresentationEvent.Subscribe(動作的動作,ThreadOption threadOption,布爾keepSubscriberReferenceAlive,謂詞濾波器)

在該方法中,「過濾器「參數被檢查。如果過濾器不爲空,則處理繼續正確。但是,如果此參數爲null,則會創建一個新的傳遞代理(始終返回true)並將其用於過濾器。錯誤在於從此傳遞代理創建的DelegateReference對象將keepReferenceAlive參數硬編碼爲值「true」。這個值不應該被硬編碼,而應該傳入傳入參數keepSubscriberReferenceAlive。

解決方法:

這個問題有一個簡單的解決方法。註冊訂閱時,應始終使用上述的冗長超載,並始終提供過濾器委託。不要爲過濾器參數傳遞「null」。如果訂閱不應被過濾,那麼當需要弱事件引用時(典型場景),應使用傳遞過濾代理:

EventAggregator.GetEvent()。Subscribe(MyHandler,ThreadOption.PublisherThread,false ,(dummy)=> true);

沒有解決方法以下簡寫過載,並且這些不應被使用,直到底層錯誤已被修補:

CompositePresentationEvent.Subscribe(動作動作) CompositePresentationEvent.Subscribe(動作的動作,ThreadOption threadOption) CompositePresentationEvent.Subscribe(行動行動,布爾keepSubscriberReferenceAlive) CompositePresentationEvent.Subscribe(行動行動,threadOption threadOption,布爾keepSubscriberReferenceAlive)

1

經過進一步的研究,我發現這個線程: http://compositewpf.codeplex.com/Thread/View.aspx?ThreadId=57362

我沒有意識到的是,訂閱電話竟是在調用堆棧或我早就意識到這點。這裏是摘錄:

Silverlight does not support weak references to lambda expressions or anonymous delegates. Therefore, the filter parameter must be a separate method if you are targeting Silverlight.

您是否試圖使用lambda作爲您的訂閱處理程序?如果是這樣,它看起來像你需要做的就是使用一個真正的方法。

EventService.GetEvent<GenericEvent<string>>().Subscribe(YourAction) 

..... 

public void YourAction(string topic) 
{ 
    if(topic == "something") 
    { 
     // more code 
    } 
} 
+0

我也被這個問題困住了,但我不認爲這是問題的答案,因爲他當他認真閱讀訂閱方法時,訂閱是有效的。 –

+0

Doh,我犯了和你原來一樣的錯誤。如果實際上Subscribe()失敗,那麼我不確定發生了什麼。問題中顯示的代碼不使用lambda。也許Konamiman是對的。我認爲如果他通過了真正的事件,這個事件還是行得通的,這將消除它是一種非公開的方法...... –

1

ShowViewAHasBeenRequested方法是公開的嗎?如果不是,調用代碼將無法訪問它。

+0

這對於在棱鏡事件中記住的事情絕對是一件好事,但我不認爲它是答案如果他將True傳遞給訂閱方法,則該事件將起作用。 –

0

當事件發佈時,您的ViewModel是否超出範圍?在Subscribe方法中傳遞True會創建一個強大的參考,這會使訂閱者在超出範圍之後無法獲取GC'd。瞭解這樣做會造成內存泄漏,因爲您實例化的每個ViewModel將繼續存在並響應已發佈的事件。

我一些訂閱設置我的模塊的初始化方法內活動時,遇到了同樣的問題 - 據我所知沒有抱着我的模塊的引用它做的一切設置完畢後。

+0

如何檢查viewModel是否超出範圍? –

0

我有完全相同的問題,並通過使兩個過濾器解決了它方法和行動方法公開爲每個用戶188067和Konamiman的迴應。即

showViewAEvent.Subscribe(ShowViewAHasBeenRequested, ThreadOption.UIThread, false, ShouldHandleEvent); 

public bool ShouldHandleError(object obj) 
{ 
    return true; 
} 

public void ShowViewAHasBeenRequested(object obj) 
{ 
... 
}