Подписка на событие с призмой, предоставляющей исключение метода доступа - PullRequest
2 голосов
/ 28 октября 2009

У меня есть событие, на которое я подписываюсь в View Model.Подписка на событие выполняется в конструкторе модели представления, которая создается с помощью единицы.

Я обнаружил, что если я подписываюсь как:

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.

Ответы [ 5 ]

4 голосов
/ 01 ноября 2009

Это известная проблема, полностью задокументированная здесь:

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

Ошибка в CompositePresentationEvent <>. Subscribe () предотвращает слабые ссылки на события. Требуется заголовок

Описание Описание обязательно ОБЗОР:

Метод Subscribe () этого класса задокументирован как создающий WeakReferences по умолчанию или если он указан как keepSubscriberReferenceAlive = false в перегрузках, которые включают этот параметр.

ОПИСАНИЕ:

Это поведение корректно наблюдается только при наличии делегата фильтра. Во всех других случаях (и всех перегрузках метода Subscribe ()) создается надежная ссылка - независимо от задокументированного значения по умолчанию и независимо от любого предоставленного значения для параметра keepSubscriberReferenceAlive.

Источник этой ошибки может быть найден в следующей перегрузке этого метода:

CompositePresentationEvent.Subscribe (Действие действия, ThreadOption threadOption, bool keepSubscriberReferenceAlive, Предикатный фильтр)

В этом методе проверяется параметр «фильтр». Если фильтр не равен нулю, обработка продолжается правильно. Однако если этот параметр имеет значение null, то для фильтра создается новый сквозной делегат (всегда возвращает значение true). Ошибка заключается в том, что объект DelegateReference, созданный из этого сквозного делегата, имеет параметр keepReferenceAlive, жестко запрограммированный в значение «true». Это значение не должно быть жестко запрограммировано, и вместо этого должен быть передан входящий параметр keepSubscriberReferenceAlive.

Временное решение:

Существует простой обходной путь для этой проблемы. При регистрации подписки вы всегда должны использовать подробную перегрузку, указанную выше, и всегда предоставлять делегат фильтра. Никогда не передавайте «ноль» для параметра фильтра. Если подписка не должна фильтроваться, тогда делегат сквозного фильтра следует использовать, когда требуется слабая ссылка на событие (типичный сценарий):

EventAggregator.GetEvent (). Subscribe (MyHandler, ThreadOption.

НЕТ обходного пути для следующих сокращенных перегрузок, и их не следует использовать, пока не будет исправлена ​​основная ошибка:

CompositePresentationEvent.Subscribe (Действие действия) CompositePresentationEvent.Subscribe (Действие действия, ThreadOption threadOption) CompositePresentationEvent.Subscribe (Действие действия, bool keepSubscriberReferenceAlive) CompositePresentationEvent.Subscribe (действие Action, ThreadOption threadOption, bool keepSubscriberReferenceAlive)

1 голос
/ 30 октября 2009

Является ли метод ShowViewAHasBeenRequested общедоступным? Если нет, то он не будет доступен по вызывающему коду.

1 голос
/ 28 октября 2009

После дальнейших исследований я нашел эту тему: http://compositewpf.codeplex.com/Thread/View.aspx?ThreadId=57362

Я не осознавал, что вызов Subscribe действительно был в CallStack, или я бы понял это раньше Вот выдержка:

Silverlight не поддерживает слабые ссылки на лямбда-выражения или анонимные делегаты. Следовательно Параметр фильтра должен быть отдельным метод, если вы нацеливаетесь Silverlight.

Вы пытаетесь использовать лямбду в качестве обработчика для этой подписки? Если это так, похоже, все, что вам нужно сделать, это использовать реальный метод.

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

.....

public void YourAction(string topic)
{
   if(topic == "something")
   {
      // more code
   }
}
0 голосов
/ 11 марта 2010

У меня была точно такая же проблема, и я решил ее, обнародовав как метод фильтра, так и метод действия в соответствии с user188067 и ответами Konamiman. т.е.

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

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

public void ShowViewAHasBeenRequested(object obj)
{
...
}
0 голосов
/ 30 октября 2009

Ваш ViewModel вышел из области действия, когда событие опубликовано? Передача True в методе Subscribe создает надежную ссылку, которая не дает подписчику получить GC'd после того, как он вышел из области видимости. Поймите, что это приведет к утечке памяти, поскольку каждый экземпляр ViewModel, который вы создаете, будет продолжать жить и реагировать на эти опубликованные события.

Я столкнулся с той же проблемой, когда настраивал некоторые подписки на события внутри метода Initialize моего модуля - насколько я мог судить, ничего не было в том, чтобы хранить ссылку на мой модуль после завершения настройки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...