Search code examples
wpfviewmodelmvvm-light

MVVM Light messenger service not receiving message in view model


Not sure if I am just doing this wrong or am misunderstanding some of the examples already on stack overflow here and here.

I am trying to take a selected item from my first view model and pass it to another view model I am navigating to. The purpose of this is so I can display the item that has been passed and allow the user to work with it.

Passing from first view model

This is just a small snippet of the first view model. Here I am first navigating to the new page/view model. Then pass the SelectedRule object using a messenger. Navigation is done using a ViewModelLocator class / navigation service provided with MVVM Light.

private ApprovedBomRule _selectedRule = new ApprovedBomRule();

public ApprovedBomRule SelectedRule
{
    get { return _selectedRule;}
    set { Set(ref _selectedRule, value); }
}

private void NavigateToUpdateRule()
{
    //Navigate to Update Rule page
    _navigationService.NavigateTo("UpdateBomRuleView");
    //Pass selected rule as a parameter using messenger service
    ApprovedBomRule ruleToSend = SelectedRule; // Selected by user.
    Messenger.Default.Send(ruleToSend);
}

On receiving view model

Here is my second view model where I register the same type of SelectedRule from above and set it to the public variable.

public class UpdateBomRuleViewModel : ViewModelBase
{
    private ApprovedBomRule _passedRule;

    public ApprovedBomRule PassedRule
    {
        get => _passedRule;
        set => Set(ref _passedRule, value);
    }
    //Constructor
    public UpdateBomRuleViewModel()
    {
        //Register message type
        Messenger.Default.Register<ApprovedBomRule>(this, GetMessage);
    }
    //Set the property to passed object
    public void GetMessage(ApprovedBomRule rule)
    {
        PassedRule = rule;
    }
}

My constructor is reached and the register method is set, but the GetMessage() function is never called. What am I missing here?

EDIT

I narrowed down the problem to the fact that the register method is being called after the message is sent. Now the second problem I am running into is how do I have my second view model register before the send? I am using a viewmodel locator in my pages to determine the view models for each page. Even though I am doing the _navigation.NavigateTo() before sending the data, the view model is not initialized until after the send.

Example of viewmodel locator in page

<local:BasePage x:Class="YAI.BomConfigurator.Desktop.Views.Rules.UpdateBomRuleView"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
  xmlns:local="clr-namespace:YAI.BomConfigurator.Desktop"
  mc:Ignorable="d" 
  d:DesignHeight="450" d:DesignWidth="800"
  Title="UpdateBomRuleView"
  DataContext="{Binding UpdateBomRuleViewModel, Source={StaticResource Locator}}">

<Grid>
    <TextBlock Text="{Binding PassedRule.Description}" 
               VerticalAlignment="Center"
               HorizontalAlignment="Center">

    </TextBlock>
</Grid>


Solution

  • Okay so I sort of found a solution to the problem. I used my ServiceLocator to get the instance before navigating.

     var vm = ServiceLocator.Current.GetInstance<UpdateBomRuleViewModel>();
     //Navigate to Update Rule page
     _navigationService.NavigateTo("UpdateBomRuleView");
     //Pass selected rule as a parameter using messenger service
     ApprovedBomRule ruleToSend = SelectedRule; // Selected by user.
     Messenger.Default.Send(ruleToSend);
    

    This caused my register to be called before the send. I don't necessarily like this solution because the var vm is not being used for anything, but it works for now.

    thank you for looking at the question.