MVVM Light jest moją ulubioną biblioteką wspomagającą implementację wzorca MVVM. Używam jej w zasadzie w większości projektów WPF, a wkrótce będę testował jej wykorzystanie w Xamarin Forms.
Dzisiaj kilka słów o klasie Messenger, wchodzącej w skład tej biblioteki. W dużym skrócie, Messenger pozwala na wymianę wiadomości (messages) pomiędzy obiektami. W praktyce, stosowany jest najczęściej do wysyłania wiadomości pomiędzy ViewModel-ami. Dzięki zastosowanie Messengera możemy zredukować do minimum lub całkowicie usunąć jakiekolwiek powiązania pomiędzy ViewModel-ami. To pozwoli (przy zastosowaniu dobrej architektury) zbliżyć się do magicznego S z zestawu zasad SOLID. Jakkolwiek możliwość pełnego zachowania Single Responsibility Principle w przypadku View Modeli jest kwestią nieco dyskusyjną, to redukowanie zależności pomiędzy klasami zawsze pozytywnie wpływa na jakość i testowalność kodu.
Messenger w MVVM Light jest implementacją wzorca behavioralnego Mediator. W dużym skrócie, klasa mediatora jest klasą która posiada wiedzę o klasach którymi zarządza. Klasy nie muszą wiedzieć nic na swój temat, wykorzystują mediatora do wymiany informacji pomiędzy sobą.
Żeby skorzystać z Messengera w MVVM Light, trzeba przede wszystkim przygotować klasę dla przesyłanej wiadomości:
public class TestMessage { public string TestMessageText {get; set;} }
Teraz pozostaje zaimplementować wysyłanie wiadomości w klasie obiektu źródłowego, wykorzystamy do tego metodę Send. Następnie w klasie obiektu docelowego musimy zarejestrować chęć odbioru tej wiadomości, za pomocą metody Register. W większości przypadków tymi obiektami będą nasze ViewModel-e.
Wyślijmy więc wiadomość:
Messenger.Default.Send<TestMessage>(new TestMessage {TestMessageText="test"});
W tym najprostszym przykładzie, używamy Messengera jako klasy statycznej. Wywołując jego własność Default, otrzymując tym samym instancję domyślną tej klasy. Metoda Send przyjmuje parametr typu generycznego, którym jest nazwa klasy naszej wiadomości. Następnie inicjalizujemy obiekt naszej wiadomości.
Oczywiście nie ma konieczności używania Messengera z instancją domyślną, jest to jednak bardzo wygodne i popularne rozwiązanie w przypadku komunikacji pomiędzy ViewModel-ami.
Wysłanie komunikatu w przedstawiony powyżej sposób spowoduje odebranie go, przez wszystkie obiekty, które zarejestrowały chęć odebrania wiadomości tego typu. Jeżeli jest taka potrzeba, i chcemy wysyłać wiadomości do obiektów konkretnej klasy, możemy użyć metody Send<TMessage, TTarget>, gdzie TTarget określi typ docelowy obiektu, który ma odebrać wiadomość (oczywiście pod warunkiem, że zarejestrował taką chęć).
Przejdźmy więc do rejestracji w Messengerze chęci odbioru wiadomości:
Messenger.Default.Register<TestMessage>(this, this.ProcessMessage); private void ProcessMessage(TestMessage message) { Console.WriteLine(message); }
Rejestrację oczywiście najlepiej przeprowadzić w konstruktorze. Najczęściej używana wersja metody Register posiada strukturę Register<TMessage>(Object, Action<TMessage>).
Object – określa odbiorcę wiadomości. W większości przypadków będziemy wskazywać na obiekt, z którego dokonujemy rejestracji
Action<TMessage> – to akcja, która ma zostać wykonana w momencie gdy do naszego obiektu zostanie wysłana wiadomość określonego typu (w naszym przypadku jest to TestMessage).
Akcja (Action<T>) jest delegatem, do którego możemy przypisać metodę zwracającą void. Delegat Action posiada wiele wersji, w zależności od ilości parametrów które chcemy przekazać do metody (Action<T1,T2,….,TX>).
Co jest ważne, zarejestrowanie odbiorcy nie tworzy żadnej sztywnej referencji do niego. Jeżeli odbiorca z jakiegoś powodu zostanie skasowany – nie powstaje memory leak.
Warto zainteresować się Messengerem. Wiele osób ogranicza się do wykorzystania w MVVM Light jedynie implementacji RelayCommand i dobrodziejstw ViewModelLocator-a. Tym czasem Messenger naprawdę ułatwia życie pozwalając na wygodną wymianę danych pomiędzy ViewModel – ami okien czy stron.