Udostępnij przez


Komunikacja między luźno powiązanymi składnikami

Napiwek

Ta zawartość jest fragmentem książki eBook, wzorców aplikacji dla przedsiębiorstw przy użyciu platformy .NET, dostępnej na platformie .NET MAUIDocs lub jako bezpłatnego pliku PDF do pobrania, który można odczytać w trybie offline.

Wzorce aplikacji dla przedsiębiorstw przy użyciu miniatury książki eBook platformy .NET MAUI .

Wzorzec publikowania-subskrybowania to wzorzec obsługi komunikatów, w którym wydawcy wysyłają komunikaty bez znajomości żadnych odbiorców, znanych jako subskrybenci. Podobnie subskrybenci słuchają określonych wiadomości, nie znając żadnych wydawców.

Zdarzenia na platformie .NET implementują wzorzec publikowania-subskrybowania i są najprostszym podejściem do warstwy komunikacji między składnikami, jeśli nie jest wymagane luźne sprzęganie, takie jak kontrolka i strona, która ją zawiera. Jednak okresy istnienia wydawcy i subskrybenta są powiązane ze sobą przez odwołania do obiektów, a typ subskrybenta musi mieć odwołanie do typu wydawcy. Może to powodować problemy z zarządzaniem pamięcią, zwłaszcza gdy istnieją obiekty krótkotrwałe, które subskrybują zdarzenie obiektu statycznego lub długotrwałego. Jeśli program obsługi zdarzeń nie zostanie usunięty, subskrybent będzie nadal aktywny przez odwołanie do niego w wydawcy, co uniemożliwi lub opóźni odzyskiwanie pamięci subskrybenta.

Wprowadzenie do zestawu narzędzi MVVM Toolkit Messenger

Interfejs MVVM Toolkit IMessenger opisuje wzorzec publikowania-subskrybowania, umożliwiając komunikację opartą na komunikatach między składnikami, które są niewygodne w celu łączenia według odwołań do obiektu i typu. Ten mechanizm umożliwia wydawcom i subskrybentom komunikowanie się bez bezpośredniego odwołwania się do siebie, co pomaga zmniejszyć zależności między składnikami, jednocześnie umożliwiając niezależne opracowywanie i testowanie składników.

Uwaga

MvVM Toolkit Messenger jest częścią CommunityToolkit.Mvvm pakietu. Aby uzyskać informacje na temat sposobu dodawania pakietu do projektu, zobacz Wprowadzenie do zestawu narzędzi MVVM w Centrum deweloperów firmy Microsoft.

Ostrzeżenie

Platforma .NET MAUI zawiera wbudowaną MessagingCenter klasę, która nie jest już zalecana do użycia. Zamiast tego użyj narzędzia MVVM Toolkit Messenger.

Interfejs IMessenger umożliwia korzystanie z funkcji publikowania i subskrybowania multiemisji. Oznacza to, że może istnieć wiele wydawców, którzy publikują jeden komunikat, i może być wielu subskrybentów nasłuchujących tego samego komunikatu. Na poniższej ilustracji przedstawiono tę relację:

Funkcja publikowania-subskrybowania multiemisji.

Istnieją dwie implementacje interfejsu IMessenger , które są dostarczane z pakietem CommunityToolkit.Mvvm . Używa WeakReferenceMessenger słabych odwołań, co może spowodować łatwiejsze czyszczenie subskrybentów komunikatów. Jest to dobra opcja, jeśli subskrybenci nie mają jasno zdefiniowanego cyklu życia. Używa StrongReferenceMessenger silnych odwołań, które mogą spowodować lepszą wydajność i bardziej wyraźnie kontrolowany okres istnienia subskrypcji. Jeśli masz przepływ pracy z bardzo kontrolowanym okresem istnienia (na przykład subskrypcja powiązana z metodami i OnAppearing stronOnDisappearing), StrongReferenceManager może to być lepsza opcja, jeśli wydajność jest problemem. Obie te implementacje są dostępne z domyślnymi implementacjami gotowymi do użycia, odwołując WeakReferenceMessenger.Default się do elementu lub StrongReferenceMessenger.Default.

Uwaga

IMessenger Interfejs zezwala na komunikację między luźno powiązanymi klasami, ale nie oferuje jedynego rozwiązania architektury dla tego problemu. Na przykład komunikacja między modelem widoku a widokiem może być również osiągana przez aparat powiązania i powiadomienia o zmianie właściwości. Ponadto komunikację między dwoma modelami widoków można również osiągnąć, przekazując dane podczas nawigacji.

Aplikacja wieloplatformowa eShop używa WeakReferenceMessenger klasy do komunikowania się między luźno powiązanymi składnikami. Aplikacja definiuje pojedynczy komunikat o nazwie AddProductMessage. Element AddProductMessage jest publikowany przez klasę CatalogViewModel po dodaniu elementu do koszyka zakupów. W zamian CatalogView klasa subskrybuje komunikat i używa go do wyróżnienia produktu z animacją w odpowiedzi.

W aplikacji WeakReferenceMessenger wieloplatformowej eShop służy do aktualizowania interfejsu użytkownika w odpowiedzi na akcję wykonywaną w innej klasie. W związku z tym komunikaty są publikowane z wątku wykonywanego przez klasę, a subskrybenci odbierają komunikat w tym samym wątku.

Napiwek

Przeprowadzanie marshalingu do interfejsu użytkownika lub wątku głównego podczas wykonywania aktualizacji interfejsu użytkownika. Jeśli aktualizacje interfejsów użytkownika nie zostaną wprowadzone w tym wątku, może to spowodować awarię aplikacji lub jej niestabilnie.

Jeśli do zaktualizowania interfejsu użytkownika jest wymagany komunikat wysyłany z wątku w tle, należy przetworzyć komunikat w wątku interfejsu użytkownika w subskrybentu, wywołując metodę MainThread.BeginInvokeOnMainThread .

Aby uzyskać więcej informacji na temat Messengerprogramu , zobacz Messenger w Centrum deweloperów firmy Microsoft.

Definiowanie komunikatu

IMessenger komunikaty to obiekty niestandardowe, które zapewniają niestandardowe ładunki. Poniższy przykład kodu przedstawia AddProductMessage komunikat zdefiniowany w aplikacji wieloplatformowej eShop:

public class AddProductMessage : ValueChangedMessage<int>
{
    public AddProductMessage(int count) : base(count)
    {
    }
}

Klasa bazowa jest definiowana przy użyciu ValueChangedMessage<T> metody , gdzie T może być dowolny typ potrzebny do przekazywania danych. Zarówno wydawcy komunikatów, jak i subskrybenci mogą oczekiwać komunikatów określonego typu (na przykład AddProductMessage). Może to pomóc w zapewnieniu, że obie strony uzgodniły umowę obsługi komunikatów i że dane dostarczone z tą umową będą spójne. Ponadto takie podejście zapewnia bezpieczeństwo i refaktoryzację typu kompilacji.

Publikowanie komunikatu

Aby opublikować komunikat, musimy użyć IMessenger.Send metody . Dostęp do tej funkcji można uzyskać najczęściej za pośrednictwem programu WeakReferenceMessenger.Default.Send lub StrongReferenceMessenger.Default.Send. Wysłana wiadomość może mieć dowolny typ obiektu. W poniższym przykładzie kodu pokazano publikowanie komunikatu AddProduct :

WeakReferenceMessenger.Default.Send(new Messages.AddProductMessage(BadgeCount));

W tym przykładzie Send metoda określa nowe wystąpienie obiektu dla subskrybentów podrzędnych AddProductMessage do odbierania. Dodatkowy drugi parametr tokenu można dodać do użycia, gdy wielu różnych subskrybentów musi odbierać komunikaty tego samego typu bez odbierania nieprawidłowego komunikatu.

Metoda Send opublikuje komunikat i jego dane ładunku przy użyciu podejścia fire-and-forget. W związku z tym wiadomość jest wysyłana nawet wtedy, gdy nie ma subskrybentów zarejestrowanych w celu odebrania wiadomości. W takiej sytuacji wysłana wiadomość jest ignorowana.

Subskrybowanie wiadomości

Subskrybenci mogą zarejestrować się, aby otrzymywać komunikat przy użyciu jednego z IMessenger.Register<T> przeciążeń. Poniższy przykład kodu pokazuje, jak aplikacja wieloplatformowa eShop subskrybuje i przetwarza AddProductMessage komunikat:

WeakReferenceMessenger.Default
    .Register<CatalogView, Messages.AddProductMessage>(
        this,
        async (recipient, message) =>
        {
            await recipient.Dispatcher.DispatchAsync(
                async () =>
                {
                    await recipient.badge.ScaleTo(1.2);
                    await recipient.badge.ScaleTo(1.0);
                });
        });

W poprzednim przykładzie Register metoda subskrybuje AddProductMessage komunikat i wykonuje delegata wywołania zwrotnego w odpowiedzi na odbieranie komunikatu. Ten delegat wywołania zwrotnego określony jako wyrażenie lambda wykonuje kod, który aktualizuje interfejs użytkownika.

Uwaga

Unikaj używania this obiektu w delegacie wywołania zwrotnego, aby uniknąć przechwytywania tego obiektu w delegatu. Może to pomóc zwiększyć wydajność. Zamiast tego użyjesz parametru recipient.

Jeśli dane ładunku są dostarczane, nie próbuj modyfikować danych ładunku z poziomu delegata wywołania zwrotnego, ponieważ kilka wątków może uzyskiwać dostęp do odebranych danych jednocześnie. W tym scenariuszu dane ładunku powinny być niezmienne, aby uniknąć błędów współbieżności.

Anulowanie subskrypcji z wiadomości

Subskrybenci mogą anulować subskrypcję wiadomości, które nie chcą już otrzymywać. Jest to osiągane przy użyciu jednego IMessenger.Unregister z przeciążeń, jak pokazano w poniższym przykładzie kodu:

WeakReferenceMessenger.Default.Unregister<Messages.AddProductMessage>(this);

Uwaga

W tym przykładzie nie jest w pełni konieczne wywołanie Unregister metody , ponieważ WeakReferenceMessenger obiekt pozwoli nieużywanym obiektom na odzyskiwanie pamięci. StrongReferenceMessenger Gdyby były używane, zaleca się wywołanie Unregister wszelkich subskrypcji, które nie są już używane.

W tym przykładzie składnia Unsubscribe metody określa argument typu komunikatu i obiektu adresata, który nasłuchuje komunikatów.

Podsumowanie

Interfejs MVVM Toolkit IMessenger opisuje wzorzec publikowania-subskrybowania, umożliwiając komunikację opartą na komunikatach między składnikami, które są niewygodne w celu łączenia według odwołań do obiektu i typu. Ten mechanizm umożliwia wydawcom i subskrybentom komunikowanie się bez odwołwania się do siebie, co pomaga zmniejszyć zależności między składnikami, jednocześnie umożliwiając niezależne opracowywanie i testowanie składników.