WPF MVVM Link Between View Model

I am working on a WPF MVVM application in which I have 2 views View1 and View2 with their respective ViewModels. Now I want a button click in View1 to close View1 and open View2 using ViewModel1. In addition, I want to transfer some data, for example, an instance of the person class in ViewModel2 when opening from ViewModel1, which will be used to display information in View2.

What is the best and possibly easiest way to achieve this only in ViewModels, I would like to avoid writing code for navigation in the code.

+8
c # wpf viewmodel mvvm
source share
3 answers

How about using a mediator template (e.g. see this ) or weak events? Afaik several MVVM frameworks / libs (e.g. PRISM, Caliburn.Micro, MVVMCross) already come with the infrastructure code for them. There are also separate libraries that are independent of any particular mvvm structure, such as the Appccelerate EventBroker , which can help you achieve something according to what you want.

With events, however, I wonder if you need some feedback on whether the event was β€œcorrectly” handled or not. There are ways to achieve this (changing the value of args events, handling event synchronization, after raising the event, checking the value of the event arguments), but they are not as brief as the return value of a method, or a method that throws an exception.

EDIT: Sorry, I just realized that the second view / view model is not yet open. Therefore, my "solution" is not (it is simple) applicable. You need to pass the instruction β€œup” in the tree of the view model, perhaps even to the root directory, where you can create an instance and show the new view model (show in a new window or as a ContentControl in an existing view?)

+3
source share

I created this Messenger class to handle the connection between ViewModels.

Register for the added face object in MainViewModel :

 Messenger.Default.Register<Person>(this, AddPersonToCollection, Context.Added); 

To notify all registered ViewModels of the added person from CreatePersonViewModel :

 Messenger.Default.Send(person, Context.Added); 

Source:

 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<MessengerKey, object> Dictionary = new ConcurrentDictionary<MessengerKey, object>(); #region Default property private static Messenger _instance; /// <summary> /// Gets the single instance of the Messenger. /// </summary> public static Messenger Default { get { if (_instance == null) { lock (CreationLock) { if (_instance == null) { _instance = new Messenger(); } } } return _instance; } } #endregion /// <summary> /// Initializes a new instance of the Messenger class. /// </summary> private Messenger() { } /// <summary> /// Registers a recipient for a type of message T. The action parameter will be executed /// when a corresponding message is sent. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="recipient"></param> /// <param name="action"></param> public void Register<T>(object recipient, Action<T> action) { Register(recipient, action, null); } /// <summary> /// 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. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="recipient"></param> /// <param name="action"></param> /// <param name="context"></param> public void Register<T>(object recipient, Action<T> action, object context) { var key = new MessengerKey(recipient, context); Dictionary.TryAdd(key, action); } /// <summary> /// Unregisters a messenger recipient completely. After this method is executed, the recipient will /// no longer receive any messages. /// </summary> /// <param name="recipient"></param> public void Unregister(object recipient) { Unregister(recipient, null); } /// <summary> /// Unregisters a messenger recipient with a matching context completely. After this method is executed, the recipient will /// no longer receive any messages. /// </summary> /// <param name="recipient"></param> /// <param name="context"></param> public void Unregister(object recipient, object context) { object action; var key = new MessengerKey(recipient, context); Dictionary.TryRemove(key, out action); } /// <summary> /// Sends a message to registered recipients. The message will reach all recipients that are /// registered for this message type. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="message"></param> public void Send<T>(T message) { Send(message, null); } /// <summary> /// Sends a message to registered recipients. The message will reach all recipients that are /// registered for this message type and matching context. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="message"></param> /// <param name="context"></param> public void Send<T>(T message, object context) { IEnumerable<KeyValuePair<MessengerKey, object>> 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<Action<T>>()) { // Send the message to all recipients. action(message); } } protected class MessengerKey { public object Recipient { get; private set; } public object Context { get; private set; } /// <summary> /// Initializes a new instance of the MessengerKey class. /// </summary> /// <param name="recipient"></param> /// <param name="context"></param> public MessengerKey(object recipient, object context) { Recipient = recipient; Context = context; } /// <summary> /// Determines whether the specified MessengerKey is equal to the current MessengerKey. /// </summary> /// <param name="other"></param> /// <returns></returns> protected bool Equals(MessengerKey other) { return Equals(Recipient, other.Recipient) && Equals(Context, other.Context); } /// <summary> /// Determines whether the specified MessengerKey is equal to the current MessengerKey. /// </summary> /// <param name="obj"></param> /// <returns></returns> 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); } /// <summary> /// Serves as a hash function for a particular type. /// </summary> /// <returns></returns> public override int GetHashCode() { unchecked { return ((Recipient != null ? Recipient.GetHashCode() : 0) * 397) ^ (Context != null ? Context.GetHashCode() : 0); } } } } } 
+19
source share

Use the small, dedicated Light Message Bus . It is not part of any MVVM structure, so it can be used independently. Very easy to install and use.

Recommendations for use

+1
source share

All Articles