【问题标题】:MVVM Light messenger service not receiving message in view modelMVVM Light messenger 服务未在视图模型中接收消息
【发布时间】:2019-05-11 20:29:23
【问题描述】:

不确定我是做错了还是误解了堆栈溢出herehere 上的一些示例。

我正在尝试从我的第一个视图模型中获取选定的项目并将其传递给我正在导航到的另一个视图模型。这样做的目的是让我可以显示已通过的项目并允许用户使用它。

从第一个视图模型传递

这只是第一个视图模型的一个小sn-p。在这里,我首先导航到新的页面/视图模型。然后使用信使传递 SelectedRule 对象。导航是使用 MVVM Light 提供的 ViewModelLocator 类/导航服务完成的。

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

关于接收视图模型

这是我的第二个视图模型,我从上面注册了相同类型的 SelectedRule 并将其设置为公共变量。

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

到达我的构造函数并设置了注册方法,但从未调用 GetMessage() 函数。我在这里错过了什么?

编辑

我将问题缩小到在发送消息后调用 register 方法这一事实。现在我遇到的第二个问题是如何在发送之前注册第二个视图模型?我在我的页面中使用视图模型定位器来确定每个页面的视图模型。即使我在发送数据之前执行 _navigation.NavigateTo(),视图模型直到发送之后才会初始化。

页面中的视图模型定位器示例

<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>

【问题讨论】:

  • 我缺乏建立从SelectedRuleApprovedBomRule 的连接的信息。 SelectedRule 究竟是什么;当 Messenger.Default.Send(SelectedRule); 被调用时,调试器告诉你什么类型的对象 SelectedRule 是什么?
  • SelectedRule 是 ApprovedBomRule 类型。我将清理示例以使其更加清晰。一瞬间。 @elgonzo
  • 嗯,现在不知道。也许,除非其他人能提出有用的答案,否则请获取 MVVMLight 源代码 (github.com/lbugnion/mvvmlight) 并使用它来代替预编译的 MVVMLight 库。这将允许您调试进入 MVVMLight 信使代码以查看那里发生了什么...
  • @elgonzo 你介意投票这个问题然后看看它是否能引起更多的兴趣。谢谢。
  • 没问题...!

标签: wpf viewmodel mvvm-light


【解决方案1】:

好的,所以我找到了解决问题的方法。我在导航之前使用了我的 ServiceLocator 来获取实例。

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

这导致我的寄存器在发送之前被调用。我不一定喜欢这个解决方案,因为 var vm 没有被用于任何事情,但它现在可以工作。

感谢您查看问题。

【讨论】:

  • 仅供参考:(一个)UpdateBomRuleViewModel 实例当然必须存在以接收/处理消息。如果不存在 UpdateBomRuleViewModel 实例,如何以任何方式调用 UpdateBomRuleViewModel.GetMessage(实例方法)?您说您不喜欢您的解决方案,这让我认为您的应用程序设计/逻辑可能存在与 UpdateBomRuleViewModel 相关的缺陷。您可能想考虑是什么导致您尝试向不存在(现在/不再存在?)的 UpdateBomRuleViewModel 实例发送消息。
  • @elgonzo 是的,我知道你的意思。我相信这是我确实查看了第一个导航而不是查看模型第一个导航的事实。问题是直到导航完成并且新页面出现之后实例才被初始化。现在对我来说很有意义,但我当然还在学习!感谢您的意见,尽管我很感激我能得到的所有建议。
  • 我不能给出那么好的建议,因为我对你的项目的看法太狭隘了,基本上仅限于问题/答案/cmets中可以看到的内容。但在我看来,您在多个页面视图模型之间共享了一些状态(例如SelectedRule)。 (1/2)
  • (2/2) 正如我所说,我对您的项目了解得不够多,无法知道一种对您有好处的方法,但是您可以尝试管理状态(例如 SelectedRule 和可能的其他)在某些顶级(“主”)视图模型或“导航模型”中,并使用中介模式方法在此状态管理模型和您的视图模型之间进行交互。 (如果您的项目规模小且范围窄,您可以通过在视图模型中注入和使用状态管理模型以某种方式简化事情)
【解决方案2】:

在发送消息之前,您需要等待页面出现。奇怪的是 MVVMLight 没有像 Prism 那样提供任何 NavigateAsync 方法,所以你必须自己动手。

await Application.Current.Dispatcher.Invoke( 
    () => _navigationService.NavigateTo("UpdateBomRuleView");

ApprovedBomRule ruleToSend = SelectedRule; // Selected by user.
Messenger.Default.Send(ruleToSend);

对我的 UWP 代码稍作修改,但对 WPF 应该没问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-07
    • 2012-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多