使用事件在ViewModel之间进行通信

5

我正在尝试将子ViewModel中的事件传递回父ViewModel。子ViewModel的视图是一个单独的窗口,我认为无法向其传递构造函数参数。该视图上的按钮需要触发父ViewModel中的一个方法。

子ViewModel:

public ConnectViewModel(ConnectEvents connectEvents)
{
    ConnectEvents = connectEvents;
}

父 ViewModel

public MainWindowViewModel()
{
    ConnectEvents connectEvents = new ConnectEvents();
    ConnectViewModel = new ConnectViewModel(connectEvents);
    connectEvents.ThrowEvent += ConnectToServer;
}

这两者之间如何通信?有更好的系统吗?或者,我如何让家长订阅孩子的资料?


如果你真的想要实现MVVM,你应该看一下命令模式。 - trinaldi
能否将命令传递给另一个视图模型?它们具有不同的数据上下文。 - user547794
这是它的功能,看一下定义:http://en.wikipedia.org/wiki/Command_pattern - trinaldi
4个回答

8

7
您可以制作自己的事件聚合器。
public static class DumbAggregator
{
  public static void BroadCast(string message)
  {
   if (OnMessageTransmitted != null)
       OnMessageTransmitted(message);
  }

 public static Action<string> OnMessageTransmitted;
}

使用方法:

  public class MySender
  {
    public void SendMessage()
    {
      DumbAggregator.BroadCast("Hello There!");
    }
  }

public class MySubscriber
{
  public MySubscriber()
  {
   DumbAggregator.OnMessageTransmitted += OnMessageReceived;
  }

 private void OnMessageReceived(string message)
 {
  MessageBox.Show("I Received a Message! - " + message);
 }
}

通过这个功能,您可以与您的视图模型进行通信。


1
对于使用此代码的其他人,您可能希望让每个订阅者执行不同的操作。因此,您可以在每个类的构造函数中添加 DumbAggregator.OnMessageTransmitted += OnMessageReceived; 而无需创建一个新的类,然后根据接收到的消息创建特定的 if 语句。这样可以提供很大的灵活性。 - wdlax11

2
使用事件来传递“事件”
在你的ConnectViewModel中...
public ConnectViewModel(ConnectEvents connectEvents)
{
    public event EventHandler<EventArgs> SomethingHappenedEvent;

     ...

     private void DoSomething()
     {
          if (SomethingHappenedEvent != null)
          {
              SomethingHappenedEvent(this, newEventArgs());
          }
     }

     RelayComand _somethingCommand;
     public ICommand SomethingHappenedCommand
     {   
          get
          {
              if (_someethingCommand == null)
                   _somethingCommand = new RelayCommand(DoSomething)
           }
     }
}

在你的MainWindowViewModel中

public MainWindowViewModel()
{
    ConnectEvents connectEvents = new ConnectEvents();
    ConnectViewModel = new ConnectViewModel(connectEvents);
    ConnectViewModel.SomethingHappenedEvent += HandleSomethingHappened;
    connectEvents.ThrowEvent += ConnectToServer;
}
private void HandleSomethingHappened(object sender, EventArgs e)
{
    // Now your mainviewmodel knows that something happened
}

1
这里是一个示例,利用了被采纳答案中提到的WeakEventManager
namespace Stuff {
    using System;
    using System.Windows;

    // An "event bus" public to all view models.
    public sealed class Events {
        public static Events Instance { get; } = new Events();

        public event EventHandler<EventArgs>? SomethingHappend;

        private Events() { }

        public static void RaiseSomethingHappend(object? sender = null)
            => Instance.SomethingHappend?.Invoke(sender ?? Instance, EventArgs.Empty);
    }

    // A view model that wants to listen to one or more events.
    public class Listener {
        public Listener() {
            WeakEventManager<Events, EventArgs>.AddHandler(
                source: Events.Instance,
                eventName: nameof(Events.SomethingHappend),
                Handle);
        }

        private void Handle(object? sender, EventArgs args) { }
    }

    // A view model that raises events.
    public class Source {
        public void Foo() {
            Events.RaiseSomethingHappend();
        }
    }
}

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