Lose Kommunikation zwischen ViewModels – Teil 2

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.

Download WPF Messaging Demo

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.

Veröffentlicht von Norbert Eder

Ich bin ein leidenschaftlicher Softwareentwickler. Mein Wissen und meine Gedanken teile ich nicht nur hier im Blog, sondern auch in Fachartikeln und Büchern.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Cookie-Einstellungen
Auf dieser Website werden Cookie verwendet. Diese werden für den Betrieb der Website benötigt oder helfen uns dabei, die Website zu verbessern.
Alle Cookies zulassen
Auswahl speichern
Individuelle Einstellungen
Individuelle Einstellungen
Dies ist eine Übersicht aller Cookies, die auf der Website verwendet werden. Sie haben die Möglichkeit, individuelle Cookie-Einstellungen vorzunehmen. Geben Sie einzelnen Cookies oder ganzen Gruppen Ihre Einwilligung. Essentielle Cookies lassen sich nicht deaktivieren.
Speichern
Abbrechen
Essenziell (1)
Essenzielle Cookies werden für die grundlegende Funktionalität der Website benötigt.
Cookies anzeigen