View Model之间的WPF MVVM通信
我正在研究WPF MVVM应用程序,其中我有两个视图View1和View2及其各自的ViewModel。 现在,我希望单击View1中的按钮将关闭View1并使用ViewModel1打开View2。 此外,我想从ViewModel1打开时向ViewModel2传递一些人类实例,该实例将用于在View2中显示信息。
在ViewModels中实现这一目标的最佳方式和最简单方法是什么,我希望避免在代码后面编写导航代码。
如何使用Mediator模式(例如参见technical-recipes.com或John Smith )或弱事件? Afaik的几个MVVM框架/库(如PRISM,Caliburn.Micro,MVVMCross)已经为这些提供了基础设施代码。 还有独立于任何特定mvvm框架的独立库,如Appccelerate EventBroker ,它可以帮助您实现您想要的某些内容。
但是,对于事件,我想知道您是否需要一些反馈是否“正确”处理了事件。 有办法实现这一点(改变事件args的值,处理事件同步,提升事件,检查事件args的值),但它们不像方法的返回值或抛出exception的方法那样简洁。
编辑:抱歉,我刚刚意识到第二个视图/ viewmodel尚未打开。 所以我的“解决方案”不适用(简单地说)。 您需要在视图模型树中“up”传递指令,甚至可以传递给根,您可以在其中实例化并显示新的视图模型(在新窗口中显示或在现有视图中显示为ContentControl?)
我创建了这个Messenger
类来处理ViewModels之间的通信。
在MainViewModel
注册添加的人物对象:
Messenger.Default.Register(this, AddPersonToCollection, Context.Added);
要从CreatePersonViewModel
通知所有已注册的ViewModel有关添加的人员:
Messenger.Default.Send(person, Context.Added);
源代码:
using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; namespace Application.Messaging { public class Messenger { private static readonly object CreationLock = new object(); private static readonly ConcurrentDictionary Dictionary = new ConcurrentDictionary(); #region Default property private static Messenger _instance; /// /// Gets the single instance of the Messenger. /// public static Messenger Default { get { if (_instance == null) { lock (CreationLock) { if (_instance == null) { _instance = new Messenger(); } } } return _instance; } } #endregion /// /// Initializes a new instance of the Messenger class. /// private Messenger() { } /// /// Registers a recipient for a type of message T. The action parameter will be executed /// when a corresponding message is sent. /// /// /// /// public void Register(object recipient, Action action) { Register(recipient, action, null); } /// /// Registers a recipient for a type of message T and a matching context. The action parameter will be executed /// when a corresponding message is sent. /// /// /// /// /// public void Register (object recipient, Action action, object context) { var key = new MessengerKey(recipient, context); Dictionary.TryAdd(key, action); } /// /// Unregisters a messenger recipient completely. After this method is executed, the recipient will /// no longer receive any messages. /// /// public void Unregister(object recipient) { Unregister(recipient, null); } /// /// Unregisters a messenger recipient with a matching context completely. After this method is executed, the recipient will /// no longer receive any messages. /// /// /// public void Unregister(object recipient, object context) { object action; var key = new MessengerKey(recipient, context); Dictionary.TryRemove(key, out action); } /// /// Sends a message to registered recipients. The message will reach all recipients that are /// registered for this message type. /// /// /// public void Send (T message) { Send(message, null); } /// /// Sends a message to registered recipients. The message will reach all recipients that are /// registered for this message type and matching context. /// /// /// /// public void Send (T message, object context) { IEnumerable> result; if (context == null) { // Get all recipients where the context is null. result = from r in Dictionary where r.Key.Context == null select r; } else { // Get all recipients where the context is matching. result = from r in Dictionary where r.Key.Context != null && r.Key.Context.Equals(context) select r; } foreach (var action in result.Select(x => x.Value).OfType>()) { // Send the message to all recipients. action(message); } } protected class MessengerKey { public object Recipient { get; private set; } public object Context { get; private set; } /// /// Initializes a new instance of the MessengerKey class. /// /// /// public MessengerKey(object recipient, object context) { Recipient = recipient; Context = context; } /// /// Determines whether the specified MessengerKey is equal to the current MessengerKey. /// /// /// protected bool Equals(MessengerKey other) { return Equals(Recipient, other.Recipient) && Equals(Context, other.Context); } /// /// Determines whether the specified MessengerKey is equal to the current MessengerKey. /// /// /// public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != GetType()) return false; return Equals((MessengerKey)obj); } /// /// Serves as a hash function for a particular type. /// /// public override int GetHashCode() { unchecked { return ((Recipient != null ? Recipient.GetHashCode() : 0) * 397) ^ (Context != null ? Context.GetHashCode() : 0); } } } } }
使用微小的专用Light Message Bus 。 它不是任何MVVM框架的一部分,因此可以独立使用它。 非常容易安装和使用。
使用指南