Im Beitrag Lose Kommunikation zwischen ViewModels habe ich eine Möglichkeit der Kommunikation unter ViewModels vorgestellt. Diese enthielt noch einen kleinen Bug, der mit der aktualisierten Variante ausgebessert wurde. Zudem wurde das Interface IMessenger
um eine weitere Überladung der Methode Unregister
erweitert.
interface IMessenger
{
void Register<TNotification>(object recipient, Action<TNotification> action);
void Register<TNotification>(object recipient, string identCode, Action<TNotification> action);
void Send<TNotification>(TNotification notification);
void Send<TNotification>(TNotification notification, string identCode);
void Unregister<TNotification>(object recipient);
void Unregister<TNotification>(object recipient, string identCode);
}
Es war zwar die Möglichkeit geboten, eine Objekt-Instanz über einen Identification Code zu registrieren, ein Entfernen genau dieser Registrierung war jedoch nicht möglich. Diese Möglichkeit ist nun gegeben.
public class Messenger : IMessenger
{
private static Messenger instance;
private static object lockObject = new object();
private Dictionary<Type, List<ActionIdentifier>> references = new Dictionary<Type,List<ActionIdentifier>>();
private Messenger() { }
public static Messenger Instance
{
get
{
lock (lockObject)
{
if (instance == null)
instance = new Messenger();
return instance;
}
}
}
#region IMessenger Members
public void Register<TNotification>(object recipient, Action<TNotification> action)
{
Register<TNotification>(recipient, null, action);
}
public void Register<TNotification>(object recipient, string identCode, Action<TNotification> action)
{
Type messageType = typeof(TNotification);
if (!references.ContainsKey(messageType))
references.Add(messageType, new List<ActionIdentifier>());
ActionIdentifier actionIdent = new ActionIdentifier();
actionIdent.Action = new WeakReferenceAction<TNotification>(recipient, action);
actionIdent.IdentificationCode = identCode;
references[messageType].Add(actionIdent);
}
public void Send<TNotification>(TNotification notification)
{
Type type = typeof(TNotification);
List<ActionIdentifier> typeActionIdentifiers = references[type];
foreach (ActionIdentifier ai in typeActionIdentifiers)
{
IActionParameter actionParameter = ai.Action as IActionParameter;
if (actionParameter != null)
actionParameter.ExecuteWithParameter(notification);
else
ai.Action.Execute();
}
}
public void Send<TNotification>(TNotification notification, string identCode)
{
Type type = typeof(TNotification);
List<ActionIdentifier> typeActionIdentifiers = references[type];
foreach (ActionIdentifier ai in typeActionIdentifiers)
{
if (ai.IdentificationCode == identCode)
{
IActionParameter actionParameter = ai.Action as IActionParameter;
if (actionParameter != null)
actionParameter.ExecuteWithParameter(notification);
else
ai.Action.Execute();
}
}
}
public void Unregister<TNotification>(object recipient)
{
Unregister<TNotification>(recipient, null);
}
public void Unregister<TNotification>(object recipient, string identCode)
{
bool lockTaken = false;
try
{
Monitor.Enter(references, ref lockTaken);
foreach (Type targetType in references.Keys)
{
foreach (ActionIdentifier wra in references[targetType])
{
if (wra.Action != null && wra.Action.Target != null && wra.Action.Target.Target == recipient)
if (String.IsNullOrEmpty(identCode) || (!String.IsNullOrEmpty(identCode) && !String.IsNullOrEmpty(wra.IdentificationCode) && wra.IdentificationCode.Equals(identCode)))
wra.Action.Unload();
}
}
}
finally
{
if (lockTaken)
Monitor.Exit(references);
}
}
#endregion
}
Die verlinkte Beispielanwendung wurde dahingehend erweitert. Ebenfalls habe ich mein Testprojekt angefügt.
Im nächsten Schritt wird von mir ein kleiner Last-/Performance-Test durchgeführt. Dieser sollte schnell zu erkennen geben, ob dieser Ansatz ressourcensparend ist, oder Optimierungen notwendig sind. Ein Einsatz dieser leichtgewichtigen Lösung sollte aber schon jetzt möglich sein. Weitere Anregungen etc. sind natürlich gerne gesehen.