Passing parameter between ViewModels using MVVMLight

6.1k Views Asked by At

I'm having a problem to pass parameters betweeen my ViewModels using the Messenger class in the MVVMLight Framework.

This is the code I'm using :

ViewModelLocator

public ViewModelLocator ()
{
    ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

    SimpleIoc.Default.Register<INavigationService, NavigationService>();

    SimpleIoc.Default.Register(() => new MainViewModel(NavigationService));
    SimpleIoc.Default.Register(() => new SecondViewModel(NavigationService));
}

public MainViewModel MainViewModel
{
    get { return SimpleIoc.Default.GetInstance<MainViewModel>(); }
}

public SecondViewModel SecondViewModel
{
    get { return SimpleIoc.Default.GetInstance<SecondViewModel>(); }
}

public INavigationService NavigationService
{
    get { return SimpleIoc.Default.GetInstance<INavigationService>(); }
}

MainViewModel

private void ShowPersonDetailsCommand(object obj)
{
    Messenger.Default.Send((Person)obj);
    _navigationService.NavigateTo(new Uri("/SecondPage.xaml", UriKind.Relative))
}

SecondViewModel

public SecondViewModel(INavigationService navigationService)
{
    _navigationService = navigationService;

    Messenger.Default.Register<Person>(
        this,
        person =>
        {
            Person = person;
        });
}

In my MainViewModel (ShowPersonDetailsCommand), I'm navigating to a SecondPage and sending a person as parameter in the Messenger class. At this point, the person is well constructed and sent as a message.

But in the SecondViewModel constructor, the person is null :(

Is there something I'm missing ?

I thinks I did something wrong ...

For your information :

  • Windows Phone 8.1 (Silverlight)

  • MVVMLight 5.0.2

  • Visual Studio 2013 Update 4

3

There are 3 best solutions below

0
On BEST ANSWER

I would suggest creating the SecondViewModel immediately as soon as it is registered in the ViewModelLocator. You can do that by using a overloaded method of Register.

SimpleIoc.Default.Register<SecondViewModel>(true);

This will make sure that ensure that the Messenger registration happens before the message is sent.

3
On

When you sent the message, the SecondViewModel was not created yet; it's only created when you access the SecondViewModel property of the ViewModelLocator. So your message was sent, and wasn't handled by anything. Then, when the SecondViewModel instance was created, the message had already been sent...

I suggest you send the message after the call to NavigateTo, it should fix the problem.

0
On

Instead of sending a message, you could pass a parameter in the NavigationServicesEx.Navigate method call.

This blog by Marco Minerva advises how to hook in to the Frame_Navigating event (that it missing from the vanilla NavigationServiceEx class) to access the argument when the destination page is navigated to.

Create the INavigable interface described in the blog:

public interface INavigable
{
    Task OnNavigatedToAsync(object parameter, NavigationMode mode);
    void OnNavigatingFrom(NavigatingCancelEventArgs e);
    void OnNavigatedFrom();
}

Add a handler for the Frame.Navigating event in the NavigationServicesEx class (with some additional plumbing, see blog) then realise the INavigable interface in your ViewModels.

You will then be able to access the parameter that you passed in your Navigate call:

NavigationServiceEx.Navigate(typeof(DestinationPage).FullName, yourParameter);

In the OnNavigatedToAsync method that you implement in your ViewModel:

public Task OnNavigatedToAsync(object parameter, NavigationMode mode)
{
    if (parameter != null)
    {
        YourThing thing = parameter as YourThing;
        this.UseYourThing(thing);
    }
    return Task.CompletedTask;
}