Passing parameter between ViewModels using MVVMLight
Asked Answered
E

3

6

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

Edik answered 7/12, 2014 at 19:47 Comment(0)
H
9

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.

Hyperopia answered 8/12, 2014 at 5:41 Comment(0)
C
1

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.

Comptometer answered 7/12, 2014 at 20:12 Comment(3)
I did it, but it doesn't change anything :(Edik
@Christophe, how is your NavigationService implemented? Can the NavigateTo method take an argument to pass to the destination page? If it can, it's probably a better way to pass data between ViewModels...Comptometer
My NavigationService can take a state (object) as an argument. But the problem is I don't want to get that argument in the code behind. Because AFAIK we can get that state only when we override the OnNavigatedTo !Edik
R
0

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;
}
Rockabilly answered 9/12, 2017 at 17:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.