Reputation: 14521
I am trying to communicate events from my child ViewModel back to the parent. The child viewmodel's view is a separate window that I believe I cannot pass constructor arguments to. A button on this view needs to trigger a method on the parent ViewModel.
Child ViewModel:
public ConnectViewModel(ConnectEvents connectEvents)
{
ConnectEvents = connectEvents;
}
Parent ViewModel
public MainWindowViewModel()
{
ConnectEvents connectEvents = new ConnectEvents();
ConnectViewModel = new ConnectViewModel(connectEvents);
connectEvents.ThrowEvent += ConnectToServer;
}
How can I communicate between these two? Is there a better system, or how can I allow the parents to subscribe to the child?
Upvotes: 5
Views: 6943
Reputation: 8500
Here's an example the utilizes the WeakEventManager mentioned in the accepted answer.
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();
}
}
}
Upvotes: 1
Reputation: 5935
You have a lot of choices. You can use custom event, you can use delegate directly, you can subscribe in your parent ViewModel to the PropertyChanged or CollectionChanged event, using either ordinary subscription, or Weak Event Pattern.
I prefer the last one because there is no need to unsubscribe from.
Upvotes: 8
Reputation: 1482
You can make your own EventAggregator
public static class DumbAggregator
{
public static void BroadCast(string message)
{
if (OnMessageTransmitted != null)
OnMessageTransmitted(message);
}
public static Action<string> OnMessageTransmitted;
}
Usage:
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);
}
}
and with the help of this you can communicate with your view models
Upvotes: 7
Reputation: 841
Communicate 'events' by using events
In your 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)
}
}
}
and in your 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
}
Upvotes: 2