Caliburn.micro - 在另一个viewmodel中的属性更改时通知viewmodel

3
我有一个程序可以连接到服务器并向其发送命令。在我的程序中,我有两个窗口,其中一个是带有文本框的工具栏,用于显示当前状态(我们将其称为“mainviewmodel”),而另一个是登录窗口,接收用户名和密码并将我登录到服务器(我们将其称为“loginviewmodel”)。
现在,为了让mainviewmodel知道loginviewmodel,我使用以下方法:
[Import]
Private LoginViewModel loginViewModel;

从mainviewmodel启动登录窗口,我有以下功能:

public void Login()
{
    if (!loginViewModel.CanInvokeLogin)
        return;
    if (loginViewModel.IsActive)
    {
        loginViewModel.Focus();
    }
else
    {
        windowManager.ShowWindow(loginViewModel);
    }
}

正如您所看到的 - 在loginviewmodel中,我有一个名为CanInvokeLogin的属性,用于指示登录是否正在进行。

在mainviewmodel中,我有一个属性,用于显示当前客户端状态(绑定到视图的文本框)。

public string TextboxDescription
{
    get
    {
        switch (AvailabilityStatus.Type)
        {
            case AvailabilityStatusType.READY:
                return ("Ready");
            case AvailabilityStatusType.BREAK:
                return (AvailabilityStatus.Reason);
            case AvailabilityStatusType.DISCONNECTED:
                if (!loginViewModel.CanInvokeLogin)
                {
                    return ("Conencting");
                }
                return ("connected");
            default:
                return ("Please wait...");
            }
        }
    }
}

我的问题是 - 在视图中,状态不会更新,除非
NotifyOfPropertyChange(() => TextboxDescription);

被称为,所以我需要在任何时候调用它。
NotifyOfPropertyChange(() => CanInvokeLogin);

正在调用,但这发生在另一个视图模型上。

那么,我如何通知主视图模型caninvokelogin已更改? 我知道我可以使用事件聚合器从一个视图模型发送消息到另一个视图模型,但这听起来像用大炮打蚊子,我敢打赌有一个更简单的方法,

任何建议?


我肯定会在这种情况下使用事件聚合器。 - eran otzap
为什么要引用视图模型呢?直接使用普通的 .NET 事件即可。 - BenjaminPaul
有没有聚合器的原因,而不是像建议的那样注册事件?Eran? - Koby Yehezkel
事件聚合器是一个不错的工具,如果你需要广播整个应用的内容。例如,当用户注销应用程序时,或者其他系统中的许多类需要对这些事件做出反应时,我可能会使用事件聚合器。但在你提供的例子中,普通的事件是一个不错的解决方案...就像你说的那样...别用大炮打蚊子。 - BenjaminPaul
最终我转而使用事件聚合器 - 使用事件导致我的程序陷入停滞,每次用户断开和连接时都会发送更多的属性更改事件,可能是因为我写得不好,所以我仍在测试它,但似乎使用Caliburn消息比使用事件更优秀,在这种情况下至少是这样 :) - Koby Yehezkel
1个回答

4

处理属性变更事件

PropertyChanged事件仅仅是一个事件,如果您需要的话,可以自由地从另一个视图模型监听该事件。

this.loginViewModel.PropertyChanged += this.OnLoginPropertyChanged;

事件处理程序方法可能如下所示...
private void OnLoginPropertyChanged(object sender, PropertyChangedEventArgs e)
{
    if (e.PropertyName == "TextboxDescription") {
        // Do something.
    }
}

触发StatusChanged事件:

说实话,如果我自己来实现这个功能,我会直接在LoginViewModel中触发状态变化的事件,然后处理这些事件,这似乎是一个更加简洁的解决方案。

this.loginViewModel.StatusChanged += this.OnLoginStatusChanged;

private void OnLoginStatusChanged(object sender, LoginStatusChangedEventArgs e)
{
    // Do something.
    switch (e.StatusType)
    {
        ...
    }
}

我会像这样创建自定义事件参数...
public class LoginStatusChangedEventArgs : EventArgs
{
     public AvailabilityStatusType StatusType { get; set; }
}

当状态改变时,只需触发此事件,便可由监听器处理。

事件聚合器:

您也可以使用事件聚合器,但除非您有很多需要监听此事件的不相关类,否则我可能会觉得这是过度设计。

this.eventAggregator.Publish(new LoginStatusChangedMessage(AvailabilityStatusType.Disconnected));

1
无法编辑并错过了答案的其余部分 :) 我不喜欢发布事件的想法,因为你不应该登录超过一次(或者如果由于某种原因你感到无聊/QA并决定多次登录和注销),我发布的代码只是所需的,其余部分更多或少按照您的建议实现。 - Koby Yehezkel

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