Kommunikation zwischen lose gekoppelten Komponenten

Hinweis

Dieses E-Book wurde im Frühjahr 2017 veröffentlicht und seitdem nicht mehr aktualisiert. Es gibt vieles im Buch, das wertvoll bleibt, aber ein Teil des Materials ist veraltet.

Das Veröffentlichen-Abonnieren-Muster ist ein Messagingmuster, bei dem Herausgeber Nachrichten senden, ohne über Kenntnisse zu Empfängern zu verfügen, die als Abonnenten bezeichnet werden. Auf ähnliche Weise lauschen Abonnenten auf bestimmte Nachrichten, ohne dass sie über Kenntnisse zu Herausgebern verfügen.

Ereignisse in .NET implementieren das Veröffentlichen-Abonnieren-Muster und sind der einfachste und unkomplizierteste Ansatz für eine Kommunikationsschicht zwischen Komponenten, wenn keine lose Kopplung erforderlich ist, wie beispielsweise ein Steuerelement und die Seite, die es enthält. Die Lebensdauer von Herausgeber und Abonnent sind jedoch durch Objektverweise miteinander gekoppelt, und der Abonnententyp muss einen Verweis auf den Herausgebertypen haben. Dies kann zu Problemen bei der Speicherverwaltung führen, insbesondere wenn es kurzlebige Objekte gibt, die ein Ereignis eines statischen oder langlebigen Objekts abonnieren. Wenn der Ereignishandler nicht entfernt wird, bleibt der Abonnent durch den Verweis darauf im Herausgeber erhalten, was die Garbage Collection des Abonnenten verhindert oder verzögert.

Einführung in MessagingCenter

Die Xamarin.FormsMessagingCenter -Klasse implementiert das Publish-Subscribe-Muster und ermöglicht die nachrichtenbasierte Kommunikation zwischen Komponenten, die durch Objekt- und Typverweise nicht verknüpft werden können. Dieser Mechanismus ermöglicht die Kommunikation zwischen Herausgebern und Abonnenten, ohne dass ein Verweis aufeinander besteht, und trägt dazu bei, die Abhängigkeiten zwischen Komponenten zu verringern. Zudem können Komponenten unabhängig voneinander entwickelt und getestet werden.

Die MessagingCenter-Klasse bietet Multicast-Funktionen zum Veröffentlichen und Abonnieren. Dies bedeutet, dass mehrere Herausgeber vorhanden sein können, die eine einzelne Nachricht veröffentlichen, und mehrere Abonnenten, die auf dieselbe Nachricht lauschen. Abbildung 4-1 veranschaulicht diese Beziehung:

Multicastfunktionen für Veröffentlichungen und Abonnements

Abbildung 4-1: Multicastfunktionen für Veröffentlichungen und Abonnements

Herausgeber senden Nachrichten mithilfe der MessagingCenter.Send-Methode, während Abonnenten mithilfe der MessagingCenter.Subscribe-Methode auf Nachrichten lauschen. Darüber hinaus können Abonnenten bei Bedarf mit der MessagingCenter.Unsubscribe-Methode auch Nachrichtenabonnements kündigen.

Intern verwendet die MessagingCenter-Klasse schwache Verweise. Dies bedeutet, dass Objekte nicht aktiv bleiben und Garbage Collection ermöglicht wird. Daher sollte es nur erforderlich sein, eine Nachricht zu kündigen, wenn eine Klasse die Nachricht nicht mehr empfangen möchte.

Die mobile eShopOnContainers-App verwendet die MessagingCenter -Klasse, um zwischen lose gekoppelten Komponenten zu kommunizieren. Die App definiert drei Nachrichten:

  • Die AddProduct-Nachricht wird von der CatalogViewModel-Klasse veröffentlicht, wenn ein Element dem Warenkorb hinzugefügt wird. Im Gegenzug abonniert die BasketViewModel Klasse die Nachricht und erhöht die Anzahl der Elemente im Warenkorb als Antwort. Darüber hinaus wird die BasketViewModel -Klasse auch von dieser Nachricht abbestellt.
  • Die Filter Meldung wird von der CatalogViewModel -Klasse veröffentlicht, wenn der Benutzer einen Marken- oder Typfilter auf die aus dem Katalog angezeigten Elemente anwendet. Im Gegenzug abonniert die CatalogView -Klasse die Nachricht und aktualisiert die Benutzeroberfläche, sodass nur Elemente angezeigt werden, die den Filterkriterien entsprechen.
  • Die ChangeTab Nachricht wird von der MainViewModel -Klasse veröffentlicht, wenn die CheckoutViewModel zu der MainViewModel folgenden erfolgreichen Erstellung und Übermittlung einer neuen Bestellung navigiert. Im Gegenzug abonniert die MainView Klasse die Nachricht und aktualisiert die Benutzeroberfläche, sodass die Registerkarte Mein Profil aktiv ist, um die Bestellungen des Benutzers anzuzeigen.

Hinweis

Die MessagingCenter-Klasse ermöglicht zwar die Kommunikation zwischen lose gekoppelten Klassen, bietet aber nicht die einzige Architekturlösung für dieses Problem. Beispielsweise kann die Kommunikation zwischen einem Ansichtsmodell und einer Ansicht auch durch die Bindungs-Engine und Benachrichtigungen über Eigenschaftsänderungen erreicht werden. Darüber hinaus kann die Kommunikation zwischen zwei Ansichtsmodellen auch durch die Übergabe von Daten während der Navigation erreicht werden.

In der mobilen eShopOnContainers-App wird verwendet, MessagingCenter um die Benutzeroberfläche als Reaktion auf eine Aktion in einer anderen Klasse zu aktualisieren. Daher werden Nachrichten im UI-Thread veröffentlicht, wobei Abonnenten die Nachricht im selben Thread empfangen.

Tipp

Marshallen Sie beim Ausführen von Benutzeroberflächenupdates im Ui-Thread. Wenn eine Nachricht, die von einem Hintergrundthread gesendet wird, zum Aktualisieren der Benutzeroberfläche erforderlich ist, verarbeiten Sie die Nachricht im UI-Thread im Abonnenten, indem Sie die Device.BeginInvokeOnMainThread-Methode aufrufen.

Weitere Informationen zu MessagingCenterfinden Sie unter MessagingCenter.

Definieren einer Nachricht

MessagingCenter-Nachrichten sind Zeichenfolgen, die zum Identifizieren von Nachrichten verwendet werden. Das folgende Codebeispiel zeigt die in der mobilen eShopOnContainers-App definierten Nachrichten:

public class MessageKeys  
{  
    // Add product to basket  
    public const string AddProduct = "AddProduct";  

    // Filter  
    public const string Filter = "Filter";  

    // Change selected Tab programmatically  
    public const string ChangeTab = "ChangeTab";  
}

In diesem Beispiel werden Nachrichten mithilfe von Konstanten definiert. Der Vorteil dieses Ansatzes besteht darin, dass er Unterstützung für Typsicherheit zur Kompilierzeit und Refactoring bietet.

Veröffentlichen einer Nachricht

Herausgeber benachrichtigen Abonnenten einer Nachricht mit einer der MessagingCenter.Send-Überladungen. Im folgenden Codebeispiel wird gezeigt, wie die AddProduct-Nachricht veröffentlicht wird:

MessagingCenter.Send(this, MessageKeys.AddProduct, catalogItem);

In diesem Beispiel gibt die Send -Methode drei Argumente an:

  • Mit dem ersten Argument wird die Absenderklasse angegeben. Die Absenderklasse muss von allen Abonnenten angegeben werden, die die Nachricht empfangen möchten.
  • Das zweite Argument gibt die Nachricht an.
  • Das dritte Argument gibt die Nutzlastdaten an, die an den Abonnenten gesendet werden sollen. In diesem Fall handelt es sich bei den Nutzlastdaten um eine CatalogItem instance.

Die Send-Methode veröffentlicht die Nachricht sowie alle ihre Nutzdaten unter Verwendung eines Fire-and-Forget-Ansatzes. Daher wird die Nachricht auch dann gesendet, wenn für den Empfang der Nachricht keine Abonnenten registriert sind. Unter diesen Umständen wird die gesendete Nachricht ignoriert.

Hinweis

Die MessagingCenter.Send-Methode kann generische Parameter verwenden, um zu steuern, wie Nachrichten übermittelt werden. Daher können mehrere Nachrichten, die eine Nachrichtenidentität gemeinsam nutzen, aber unterschiedliche Nutzdatentypen senden, von verschiedenen Abonnenten empfangen werden.

Abonnieren einer Nachricht

Abonnenten können sich registrieren, um eine Nachricht mit einer der MessagingCenter.Subscribe-Überladungen zu empfangen. Im folgenden Codebeispiel wird veranschaulicht, wie die mobile eShopOnContainers-App die AddProduct Nachricht abonniert und verarbeitet:

MessagingCenter.Subscribe<CatalogViewModel, CatalogItem>(  
    this, MessageKeys.AddProduct, async (sender, arg) =>  
{  
    BadgeCount++;  

    await AddCatalogItemAsync(arg);  
});

In diesem Beispiel abonniert die Subscribe -Methode die AddProduct Nachricht und führt einen Rückrufdelegat als Reaktion auf den Empfang der Nachricht aus. Dieser Rückrufdelegat, der als Lambdaausdruck angegeben wird, führt Code aus, der die Benutzeroberfläche aktualisiert.

Tipp

Erwägen Sie die Verwendung unveränderlicher Nutzlastdaten. Versuchen Sie nicht, die Nutzlastdaten innerhalb eines Rückrufdelegaten zu ändern, da mehrere Threads gleichzeitig auf die empfangenen Daten zugreifen können. In diesem Szenario sollten die Nutzdaten unveränderlich sein, um Parallelitätsfehler zu vermeiden.

Ein Abonnent muss möglicherweise nicht jede Instanz einer veröffentlichten Nachricht verarbeiten, und dies kann durch die generischen Typargumente gesteuert werden, die für die Subscribe-Methode angegeben werden. In diesem Beispiel empfängt AddProduct der Abonnent nur Nachrichten, die von der CatalogViewModel -Klasse gesendet werden, deren Nutzlastdaten eine CatalogItem instance sind.

Abmeldung von einer Nachricht

Abonnenten können Nachrichten kündigen, die Sie nicht mehr erhalten möchten. Dies wird mit einer der MessagingCenter.Unsubscribe-Überladungen erreicht, wie im folgenden Codebeispiel gezeigt:

MessagingCenter.Unsubscribe<CatalogViewModel, CatalogItem>(this, MessageKeys.AddProduct);

In diesem Beispiel spiegelt die Methodensyntax Unsubscribe die Typargumente wider, die beim Abonnieren der AddProduct Nachricht angegeben wurden.

Zusammenfassung

Die Xamarin.FormsMessagingCenter -Klasse implementiert das Publish-Subscribe-Muster und ermöglicht die nachrichtenbasierte Kommunikation zwischen Komponenten, die durch Objekt- und Typverweise nicht verknüpft werden können. Dieser Mechanismus ermöglicht die Kommunikation zwischen Herausgebern und Abonnenten, ohne dass ein Verweis aufeinander besteht, und trägt dazu bei, die Abhängigkeiten zwischen Komponenten zu verringern. Zudem können Komponenten unabhängig voneinander entwickelt und getestet werden.