2012-03-28 7 views
0

Ich habe folgendes Verhalten:MVVM Licht werfende Nachrichten

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)); 
... 
    } 

Es nutzt grundsätzlich die NavigateToPageAction (erhältlich in Mischung auch), sondern ermöglicht es mir auch ein Ansichtsmodell Objekt auszustrahlen (ich benutze es der Firma List Seite zu navigieren Detailseite und das ausgewählte Objekt zu übergeben)

XAML würde wie folgt aussehen: (die PassedObject Bindung ist auf eine Instanz DetailViewModel, die von ViewModelBase erbt)

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

Jetzt möchte ich für die Nachricht registrieren:

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

Aber das funktioniert nicht. Was funktioniert, ist, sich für NavigatingMessage<ViewModelBase> zu registrieren und dann die empfangene Nachricht an NavigatingMessage<DetailViewModel> zu übertragen. Gibt es einen Weg dahin?

Kann dies geschehen, damit der Messenger den tatsächlichen Typ des gesendeten Objekts erkennt und korrekt an Objekte übermittelt, die für diesen Typ registriert sind?

+0

Warum funktioniert es nicht? Erhalten Sie einen Kompilierungsfehler? Eine Ausnahme? –

+0

Nein, die Nachricht wird einfach nicht gesendet –

+0

Kannst du nicht die Nachricht vom richtigen Typ senden? –

Antwort

2

Ein möglicher Weg wäre, Reflektion zu verwenden, um die Nachricht zu senden, indem die Nachricht mit dem richtigen generischen Typ zur Laufzeit erstellt wird.
würde Eine weitere dynamic und Typinferenz zu verwenden sein:

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); 
} 

Die Version Reflexion ist ein bisschen chaotisch mit:

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 }); 
} 

Dieser Code geht davon aus, dass NavigationToken ein string ist. Wenn nicht, ändern Sie einfach den Typ des zweiten Parameters der Methode Send. Wenn Messenger nur eine Überladung der Methode Send enthält, können Sie die Bedingung in Single vereinfachen. Auf der anderen Seite, wenn es viele Überladungen dieser Methode gibt, müssen Sie es möglicherweise verfeinern.

+0

Können Sie ein Beispiel für den Reflexionsansatz geben? Ich wende mich an WP7, das, wie sich herausstellt, das dynamische Keyword –

+0

@ TomášBezouška nicht unterstützt: Siehe update. –

+0

a-may-zing :) Ich musste es ein wenig ändern (entfernte die Bedingung nach Count() == 2, da es Ausnahmen ausgelöst hat und anstelle von "method.MakeGenericMethod (viewModelType)" habe ich "method.MakeGenericMethod (messageType) "und es funktioniert wie ein Charme :) Ich hatte keine Ahnung, Reflexion hatte solche Möglichkeiten :) –

0

Wenn Sie die Nachricht senden als Messenger.Default.Send<NavigatingMessage<DetailViewModel>>(new NavigatingMessage<DetailViewModel>(this, PassedObject) Sie können die Nachricht erhalten, wie Sie möchten, ohne zu werfen.

+0

Ja, aber das würde den Zweck des Verhaltens besiegen - Ich möchte in der Lage sein, jedes Objekt zu senden, das von der ViewModelBase –

+0

mmm erbt dann habe ich Angst, Sie müssten mit Casting leben :( –

+0

@LOSTCODER: Das ist nicht Bitte, siehe meine Antwort, vielleicht lernst du etwas Neues :-) –

0

Dies ist eine Einschränkung der aktuellen Version von MVVM Light. Ich denke daran, das in Zukunft zu verbessern, aber es ist ziemlich schwierig ...

+0

Bitte werfen Sie einen Blick auf meine Antwort. Würde dies helfen, dieses Feature zu implementieren? Das DLR ist ziemlich mächtig. –

Verwandte Themen