Mvvm Light Messenger消息未收到。

3

我遇到了一个奇怪的问题。

我正在使用GalaSoft的MVVM Light框架,到目前为止一切都运行得很好。 我使用信使系统在ViewModel之间发送消息,一切正常,直到我尝试执行以下操作:

我有一个单例类GateKeeper,用于发送消息。

这个类不是ViewModel,因此不继承ViewModelBase

如果它发送消息,则不会在任何地方接收到。

我已经尝试过以下方法:

  1. GateKeeper继承ViewModeBase -> 没有成功。
  2. 注册GateKeeper以接收消息,从而查看是否会捕获/接收实际从其本身发送的消息 -> 没有成功。
  3. GateKeeper从Singleton更改为普通实例化 ->未成功
  4. 创建一个MVVM ViewModel,未连接到视图,让它像GateKeeper一样发送消息 -> 未成功

我所有连接到视图的ViewModel都可以发送消息并接收到它们。

似乎视图模型在信使工作之前必须与视图“链接”,但我认为这是一个主要的限制。

下面是当前非常简化的设置。

调用GateKeeper上的ApplicationInitialize不会触发消息在mainviewmodel或GateKeeper类本身上接收到。

我希望有人能对这个问题提出建议。

谢谢..

示例设置: MainViewModel构造函数:

 public MainViewModel()
    {
        Messenger.Default.Register<LoadViewMessage>(this, (message) =>
        {
            if (message.Sender is GateKeeper) CurrentView = message.View;
            else if (message.Sender is LoginViewModel) CurrentView = message.View;
            else if (message.Sender is MenuItemBarViewModel) CurrentView = message.View;
        });

GateKeeper:
门卫:
 public class GateKeeper : IGateKeeper
{
    private readonly IEmployeeService _employeeService;

    #region Implementation of IGateKeeper

    public void ApplicationInitialize()
    {
        Messenger.Default.Send<LoadViewMessage>(new LoadViewMessage(ObjectLocator.MainMapView), this);
    }

    public void LoginSucceeded(Employee employee)
    {
        //This is where we retrieve the available services for the current employee
        //TODO: add methods for retrieving service info from backend

        //Send a message that should make the mainview load the map into its currentview property
        Messenger.Default.Send(new LoadViewMessage(ObjectLocator.MainMapView), this);
    }

    #endregion

    public GateKeeper(IEmployeeService employeeService)
    {
        _employeeService = employeeService;

        //Test.. Is not triggered
        //Just used for debugging, thus nothing happens inhere.
        Messenger.Default.Register<LoadViewMessage>(this, (message) =>
        {
            if (message.Sender is GateKeeper) ;
            else if (message.Sender is LoginViewModel) ;
            else if (message.Sender is MenuItemBarViewModel);
        });
    }

Message class: LoadViewMessage

 public class LoadViewMessage : MessageBase
{
    public UserControl View { get; protected set; }

    public LoadViewMessage(UserControl view, object sender): base(sender)
    {
        View = view;
    }

    public LoadViewMessage(UserControl view):this(view, null){}
}

PS:ObjectLocator是一个NinJect类,负责处理所有对象的实例化和生命周期。

@更新 LBugnion(MVVM Light的创建者)指出问题出在send方法上,我实际上使用了一个带有token的Send重载方法。

@在我的情况下,这不起作用。

Messenger.Default.Send(new LoadViewMessage(ObjectLocator.MainMapView), this);

这将会起作用。

Messenger.Default.Send(new LoadViewMessage(ObjectLocator.MainMapView, this));

this应该传递给loadViewMessage而不是作为token传递给Send方法。


我不知道为什么你的代码不起作用,但我可以告诉你它应该可以。消息系统与ViewModel/View关系无关。 - jv42
你调试过(断点)GateKeeper方法了吗?例如,你正在使用非默认构造函数(带参数),它被调用了吗? - jv42
没错。它应该可以工作,在我用于视图中的其他视图模型中也是如此。 我已经调试了所有内容,并且 GateKeeper 的构造函数已被调用。 我不知道为什么它在这里不起作用。 - ThBlitz
1个回答

4
您的问题在于Send方法。您正在使用带有token作为第二个参数的重载方法。您将“this”作为token传递。这意味着您(可能是错误)将消息的发送者用作token。
如果您使用了token进行发送,则还需要使用相同的token注册接收器(在这种情况下,与Send方法中使用的完全相同的实例)。由于您没有使用token进行注册,因此Messenger永远不会发送消息,这是一种优化机制。
我猜您误解了Send方法中token的用法。如果您想要构建一个“私人通信网络”,两个对象可以使用相同的token来注册/发送和建立私人通信。token只是一种方式。
在您的情况下,如果您想要将发送者与消息一起发送,则需要将发送者保存在消息本身中,这就是MessageBase和派生类所做的。
希望这能帮到您。
劳伦特

糟糕..我发现问题了!参数“this”实际上应该是我的LoadViewMessage的一部分,但是由于错误地成为Send重载方法的一部分,因此变成了一个标记。非常感谢Laurent。我会更新我的问题以反映您的答案。祝好! - ThBlitz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接