2012-03-28 4 views
0

У меня есть следующее Поведение:MVVM Light литейных сообщения

public class NavigateAndBroadcastAction : NavigateToPageAction 
     { 
      protected override void Invoke(object parameter) 
      {    
       base.Invoke(parameter); 
       Messenger.Default.Send<NavigatingMessage<ViewModelBase>>(new NavigatingMessage<ViewModelBase>(this, PassedObject), NavigationToken); 
      } 

      public ViewModelBase PassedObject 
      { 
       get { return (ViewModelBase)GetValue(PassedObjectProperty); } 
       set { SetValue(PassedObjectProperty, value); } 
      } 

      // Using a DependencyProperty as the backing store for PassedObject. This enables animation, styling, binding, etc... 
      public static readonly DependencyProperty PassedObjectProperty = DependencyProperty.Register("PassedObject", typeof(ViewModelBase), typeof(NavigateAndBroadcastAction), new PropertyMetadata(null)); 
... 
    } 

Это в основном использует NavigateToPageAction (доступное в Blend, также), но позволяет мне также транслировать объект ViewModel (я использую его, чтобы перейти из списка страницы Деталь страницы и передать выбранный объект)

Xaml будет выглядеть следующим образом: (PassedObject Привязка к экземпляру DetailViewModel который наследуется от ViewModelBase)

<i:Interaction.Triggers> 
    <i:EventTrigger EventName="MouseLeftButtonDown"> 
     <b:NavigateAndBroadcastAction TargetPage="/View/SubjectDetailPage.xaml" NavigationToken="SubjectDetailNavigationToken" PassedObject="{Binding}" /> 
    </i:EventTrigger> 
</i:Interaction.Triggers> 

Теперь я хочу, чтобы зарегистрироваться на сообщение:

Messenger.Default.Register<NavigatingMessage<DetailViewModel>>(this, NavigationToken, true, Action); 

Но это не работает. Что работает, это зарегистрироваться на NavigatingMessage<ViewModelBase>, а затем передать полученное сообщение NavigatingMessage<DetailViewModel>. Есть ли способ обойти это?

Можно ли это сделать так, чтобы посланник обнаруживал фактический тип отправляемого объекта и правильно доставлял объекты, которые регистрировались для этого типа?

+0

Почему это не работает? Вы получаете ошибку компиляции? Исключение? –

+0

Нет, сообщение просто не доставлено –

+0

Не можете ли вы отправить сообщение с правильным типом? –

ответ

2

Одним из возможных способов было бы использование отражения для отправки сообщения путем создания сообщения с правильным типом общего типа во время выполнения.
Еще один будет использовать dynamic и определение типа:

protected override void Invoke(object parameter) 
{    
    base.Invoke(parameter); 
    dynamic viewModel = PassedObject; 
    Messenger.Default.Send(GetMessage(this, viewModel), NavigationToken); 
} 

private NavigatingMessage<T> GetMessage<T>(NavigateToPageAction action, T item) 
{ 
    return new NavigatingMessage<T>(action, item); 
} 

версия с помощью отражения немного более грязный:

protected override void Invoke(object parameter) 
{    
    base.Invoke(parameter); 
    Send(PassedObject, NavigationToken); 
} 

void Send(ViewModelBase objectToSend, string navigationToken) 
{ 
    var genericMessageType = typeof(NavigatingMessage<>) 
    var viewModelType = objectToSend.GetType(); 
    var messageType = genericMessageType.MakeGenericType(viewModelType); 
    var message = Activator.CreateInstance(messageType, this, objectToSend); 

    var method = typeof(Messenger).GetMethods() 
            .Single(x => x.Name == "Send" && 
               x.GetParameters().Count() == 2 && 
               x.GetParameters() 
               .First() 
               .ParameterType 
               .GetGenericTypeDefinition() 
               == genericMessageType); 
    method.MakeGenericMethod(viewModelType) 
      .Invoke(Messenger.Default, new [] { message, navigationToken }); 
} 

Этот код предполагает, что NavigationToken является string. Если нет, просто измените тип второго параметра метода Send. Если Messenger содержит только одну перегрузку метода Send, вы можете упростить условие в Single. С другой стороны, если есть много перегрузок этого метода, вам может потребоваться его уточнить.

+0

Не могли бы вы привести пример подхода к размышлению? Я ориентируюсь на WP7, который, как оказалось, не поддерживает динамическое ключевое слово –

+0

@ TomášBezouška: см. Обновление. –

+0

a-may-zing :) Мне пришлось немного изменить его (удалил условие onther после Count() == 2, так как он выбрал исключения и вместо «method.MakeGenericMethod (viewModelType)« Я использовал »метод.MakeGenericMethod (messageType) «И это работает как шарм :) Я понятия не имел, что отражение имело такие возможности :) –

0

Если вы отправите сообщение Messenger.Default.Send<NavigatingMessage<DetailViewModel>>(new NavigatingMessage<DetailViewModel>(this, PassedObject), вы сможете получать сообщение, как пожелаете, без кастинга.

+0

Да, но это победит цель поведения - я хочу, чтобы иметь возможность отправлять любой объект, который наследуется от ViewModelBase –

+0

ммм, тогда я боюсь, что вам придется жить с кастингом :( –

+0

@LOSTCODER: Это не Пожалуйста, см. мой ответ, вы можете узнать что-то новое :-) –

0

Это ограничение текущей версии MVVM Light. Я думаю об улучшении этого в будущем, но это довольно сложно ...

+0

Пожалуйста, взгляните на мой ответ. Помогло бы это каким-либо образом в реализации этой функции? DLR достаточно мощная. –