Messenger w Prism 9.0
Messenger w Prism to bardzo ważny mechanizm do komunikacji wewnętrznej w aplikacjach, szczególnie w tych opartych na wzorcu MVVM (Model-View-ViewModel). W skrócie, jest to narzędzie umożliwiające wymianę wiadomości pomiędzy różnymi komponentami aplikacji w sposób luźno powiązany, co sprzyja lepszej organizacji kodu i unika bezpośrednich zależności między komponentami.
Messenger w Prism oparty jest na wzorcu Publish/Subscribe (Pub/Sub), co oznacza, że jedna część aplikacji (publisher) może wysyłać wiadomości, które będą odbierane przez inne części aplikacji (subscribers), które zarejestrowały się do tych wiadomości. W ten sposób można łatwo przekazywać informacje między różnymi częściami aplikacji, nie martwiąc się o bezpośrednią interakcję między nimi.
Jak działa Messenger w Prism?
W Prism Messenger oparty jest na klasie Messenger
, która znajduje się w przestrzeni nazw Prism.Messaging
. Dzięki temu mechanizmowi, różne elementy aplikacji mogą wysyłać wiadomości, które będą odbierane przez inne elementy aplikacji, bez konieczności bezpośredniej komunikacji pomiędzy nimi.
Kluczowe koncepcje:
- Publish: Komponent A (np. ViewModel) wysyła wiadomość.
- Subscribe: Komponent B (np. Inny ViewModel) subskrybuje te wiadomości i odbiera je.
- Luźne powiązanie: Komponenty nie muszą znać się nawzajem. Komponent A nie musi wiedzieć, który komponent odbiera jego wiadomość.
Wzorzec Publish/Subscribe
- Publisher (Publisher Component): Komponent wysyła wiadomość. Może to być akcja użytkownika, np. kliknięcie przycisku, zmiana stanu w aplikacji, itp.
- Subscriber (Subscriber Component): Komponent subskrybuje wiadomości, na które chce reagować. Można mieć wiele subskrybentów dla jednej wiadomości.
Przykład implementacji z użyciem Messenger:
using Prism.Mvvm;
using Prism.Commands;
using Prism.Messaging;
using System;
namespace PrismExample
{
// 1. Definiowanie klasy wiadomości
public class MyMessage
{
public string Content { get; set; }
}
public class MainWindowViewModel : BindableBase
{
private readonly IMessenger _messenger;
public DelegateCommand SendMessageCommand { get; private set; }
public MainWindowViewModel(IMessenger messenger)
{
_messenger = messenger;
// 2. Rejestracja subskrybenta
_messenger.Register<MyMessage>(this, (message) =>
{
// Reakcja na otrzymaną wiadomość
Console.WriteLine("Otrzymano wiadomość: " + message.Content);
});
// 3. Tworzenie komendy
SendMessageCommand = new DelegateCommand(SendMessage);
}
private void SendMessage()
{
// 4. Wysłanie wiadomości
_messenger.Send(new MyMessage { Content = "Wiadomość z MainWindowViewModel!" });
}
}
}
Wyjaśnienie przykładu:
- Definiowanie wiadomości: Tworzymy klasę
MyMessage
, która będzie przechowywać dane wiadomości (w tym przypadku jest to prosty ciąg znaków). W praktyce wiadomość może zawierać bardziej złożone dane. - Rejestracja subskrybenta: W
MainWindowViewModel
rejestrujemy subskrybenta, który nasłuchuje na wiadomości typuMyMessage
. Za każdym razem, gdy taka wiadomość zostanie wysłana, zostanie wywołana funkcja obsługi (w tym przypadku po prostu wypisanie treści wiadomości na konsolę). - Wysyłanie wiadomości: Używamy
_messenger.Send
, aby wysłać wiadomość. Każdy subskrybent, który zarejestrował się na ten typ wiadomości, zostanie powiadomiony o jej nadejściu. - DelegateCommand: Komenda
SendMessageCommand
jest związana z akcją użytkownika (np. kliknięciem przycisku), która powoduje wysłanie wiadomości.
Korzyści z używania Messengera:
- Luźne powiązanie: Komponenty mogą się komunikować bez konieczności bezpośredniego odwoływania się do siebie. Komponent A (wysyłający wiadomość) nie musi znać szczegółów implementacji komponentu B (odbierającego wiadomość).
- Centralna komunikacja: Dzięki Messengerowi wszystkie wiadomości w aplikacji mogą być zarządzane w centralny sposób, co ułatwia kontrolowanie przepływu informacji.
- Skalowalność: Można łatwo dodać nowych subskrybentów, bez potrzeby zmiany innych części aplikacji.
- Bezpośrednia reakcja na zmiany: Dzięki subskrypcji na różne typy wiadomości, aplikacja może na bieżąco reagować na zmiany w modelu danych, interakcje z użytkownikiem lub inne zdarzenia systemowe.
Kiedy używać Messengera w Prism?
- Wymiana danych między różnymi widokami: Jeśli chcesz, aby różne widoki lub ViewModel’e wymieniały się informacjami, ale nie chcesz tworzyć bezpośrednich zależności między nimi.
- Powiadomienia systemowe: Jeśli chcesz mieć mechanizm powiadomień wewnątrz aplikacji, np. informowanie o zakończeniu jakiegoś procesu, błędzie, itp.
- Przekazywanie informacji o zdarzeniach między komponentami: Gdy jeden komponent w aplikacji reaguje na zdarzenie, które wpływa na inne komponenty (np. kliknięcie przycisku zmienia stan innych kontrolek).
Przykład bardziej zaawansowanego użycia Messengera:
Załóżmy, że masz aplikację z różnymi ViewModel’ami, a jeden ViewModel chce wysłać powiadomienie o zakończeniu jakiegoś długotrwałego procesu do innych ViewModeli:
// Widok A - Proces z długotrwałym zadaniem
public class ProcessViewModel : BindableBase
{
private readonly IMessenger _messenger;
public DelegateCommand StartProcessCommand { get; private set; }
public ProcessViewModel(IMessenger messenger)
{
_messenger = messenger;
StartProcessCommand = new DelegateCommand(StartProcess);
}
private void StartProcess()
{
// Symulacja długotrwałego zadania
Task.Run(() =>
{
Thread.Sleep(3000); // Symulacja pracy
// Po zakończeniu procesu wysyłamy wiadomość
_messenger.Send(new MyMessage { Content = "Proces zakończony!" });
});
}
}
// Widok B - Reakcja na zakończenie procesu
public class StatusViewModel : BindableBase
{
private readonly IMessenger _messenger;
public StatusViewModel(IMessenger messenger)
{
_messenger = messenger;
// Subskrypcja na wiadomości
_messenger.Register<MyMessage>(this, (message) =>
{
// Reakcja na zakończenie procesu
Console.WriteLine("StatusViewModel otrzymał wiadomość: " + message.Content);
});
}
}
W tym przypadku, gdy proces się zakończy, ProcessViewModel
wysyła wiadomość, a StatusViewModel
reaguje na nią, np. wyświetlając komunikat na ekranie.
Podsumowanie:
Messenger w Prism to potężne narzędzie do komunikacji w aplikacjach. Dzięki wzorcowi Publish/Subscribe możesz tworzyć elastyczną, skalowalną komunikację między różnymi komponentami aplikacji, bez tworzenia twardych zależności. To kluczowe w aplikacjach opartych na MVVM, gdzie separacja odpowiedzialności i luźne powiązanie są ważne dla utrzymania czystości i organizacji kodu.