MVVM Light casting messages - PullRequest
       7

MVVM Light casting messages

0 голосов
/ 28 марта 2012

У меня есть следующее поведение:

    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>. Есть ли способ обойти это?

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

Ответы [ 3 ]

2 голосов
/ 28 марта 2012

Один из возможных способов - использовать отражение для отправки сообщения, создав сообщение с правильным универсальным типом во время выполнения.
Другой вариант - использовать 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 голосов
/ 28 марта 2012

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

0 голосов
/ 28 марта 2012

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

...