Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Rozhraní IMessenger je kontrakt pro typy, které lze použít k výměně zpráv mezi různými objekty. To může být užitečné pro oddělení různých modulů aplikace, aniž byste museli uchovávat silné odkazy na typy, na které se odkazují. Je také možné odesílat zprávy do konkrétních kanálů, jednoznačně identifikovaných tokenem a mít různé messengery v různých částech aplikace. Sada MVVM Toolkit poskytuje dvě implementace: WeakReferenceMessenger a StrongReferenceMessenger: první používá slabé odkazy interně, nabízí automatickou správu paměti příjemcům, zatímco druhá sada používá silné odkazy a vyžaduje, aby vývojáři ručně odhlásili své příjemce, když už nejsou potřeba (další podrobnosti o tom, jak zrušit registraci obslužných rutin zpráv, najdete níže), ale výměnou za to, že nabízí lepší výkon a mnohem méně využití paměti.
Platformová API:
IMessenger,WeakReferenceMessenger,StrongReferenceMessenger,IRecipient<TMessage>,MessageHandler<TRecipient, TMessage>,ObservableRecipient,RequestMessage<T>,AsyncRequestMessage<T>,CollectionRequestMessage<T>,AsyncCollectionRequestMessage<T>.
Jak to funguje
Typy implementující IMessenger odpovídají za udržování vazeb mezi příjemci (tj. příjemci zpráv) a jejich registrovanými typy zpráv spolu s příslušnými obslužnými rutinami zpráv. Jakýkoli objekt lze zaregistrovat jako příjemce pro daný typ zprávy pomocí obslužné rutiny zprávy, která bude vyvolána při každém IMessenger použití instance k odeslání zprávy tohoto typu. Je také možné odesílat zprávy prostřednictvím konkrétních komunikačních kanálů (každý identifikovaný jedinečným tokenem), aby více modulů mohlo vyměňovat zprávy stejného typu, aniž by to způsobilo konflikty. Zprávy odeslané bez tokenu používají výchozí sdílený kanál.
Existují dva způsoby registrace zpráv: buď prostřednictvím rozhraní IRecipient<TMessage>, nebo pomocí delegáta MessageHandler<TRecipient, TMessage>, který funguje jako obslužná rutina zpráv. První umožňuje registrovat všechny obslužné rutiny pomocí jediného volání RegisterAll rozšíření, které automaticky zaregistruje příjemce všech deklarovaných obslužných rutin zpráv, zatímco druhá rutina je užitečná, když potřebujete větší flexibilitu nebo když chcete jako obslužnou rutinu zprávy použít jednoduchý výraz lambda.
Jak WeakReferenceMessenger, tak StrongReferenceMessenger také poskytují vlastnost Default, která nabízí implementaci bezpečnou pro přístup z více vláken integrovanou přímo v balíčku. V případě potřeby je také možné vytvořit více instancí objektu Messenger, například pokud je jiná instance injektována prostřednictvím poskytovatele služeb DI do jiného modulu aplikace (například více oken spuštěných ve stejném procesu).
Poznámka:
Vzhledem k tomu, že typ WeakReferenceMessenger je jednodušší používat a odpovídá chování typu messenger z MvvmLight knihovny, jedná se o výchozí typ používaný typem ObservableRecipient v MVVM Toolkit.
StrongReferenceType lze stále použít předáním instance konstruktoru této třídy.
Odesílání a příjem zpráv
Zvažte použití těchto zdrojů:
// Create a message
public class LoggedInUserChangedMessage : ValueChangedMessage<User>
{
public LoggedInUserChangedMessage(User user) : base(user)
{
}
}
// Register a message in some module
WeakReferenceMessenger.Default.Register<LoggedInUserChangedMessage>(this, (r, m) =>
{
// Handle the message here, with r being the recipient and m being the
// input message. Using the recipient passed as input makes it so that
// the lambda expression doesn't capture "this", improving performance.
});
// Send a message from some other module
WeakReferenceMessenger.Default.Send(new LoggedInUserChangedMessage(user));
Představme si, že se tento typ zprávy používá v jednoduché aplikaci pro zasílání zpráv, která zobrazuje záhlaví s uživatelským jménem a profilovým obrázkem aktuálně přihlášeného uživatele, panel se seznamem konverzací a dalším panelem se zprávami z aktuální konverzace, pokud je vybraný. Řekněme, že tyto tři sekce jsou podporovány typy HeaderViewModel, ConversationsListViewModel a ConversationViewModel, respektive. V tomto scénáři může být zpráva LoggedInUserChangedMessage odeslána objektem HeaderViewModel po dokončení přihlašovací operace a oba tyto další viewmodely pro ni mohou zaregistrovat obslužné rutiny. Například ConversationsListViewModel načte seznam konverzací pro nového uživatele a ConversationViewModel zavře aktuální konverzaci, pokud existuje.
Instance IMessenger se postará o doručování zpráv všem registrovaným příjemcům. Upozorňujeme, že příjemce se může přihlásit k odběru zpráv určitého typu. Všimněte si, že zděděné typy zpráv nejsou zaregistrovány ve výchozích implementacích IMessenger, které poskytuje sada nástrojů MVVM Toolkit.
Pokud už příjemce nepotřebujete, měli byste zrušit jeho registraci, aby přestal přijímat zprávy. Registraci můžete zrušit podle typu zprávy, tokenem registrace nebo příjemcem:
// Unregisters the recipient from a message type
WeakReferenceMessenger.Default.Unregister<LoggedInUserChangedMessage>(this);
// Unregisters the recipient from a message type in a specified channel
WeakReferenceMessenger.Default.Unregister<LoggedInUserChangedMessage, int>(this, 42);
// Unregister the recipient from all messages, across all channels
WeakReferenceMessenger.Default.UnregisterAll(this);
Varování
Jak už bylo zmíněno dříve, při použití typu WeakReferenceMessenger to není striktně nutné, protože používá slabé odkazy ke sledování příjemců, což znamená, že i již nepoužívaní příjemci budou stále moci být uvolněni garbage collectorem, přestože mají stále aktivní obslužné rutiny pro zprávy. Přesto je vhodné je odhlásit, aby se zlepšil výkon. Na druhou stranu implementace StrongReferenceMessenger používá silné odkazy ke sledování registrovaných příjemců. To se provádí z výkonnostních důvodů a znamená to, že každý zaregistrovaný příjemce by měl být ručně odregistrován, aby se předešlo únikům paměti. To znamená, že dokud je příjemce zaregistrovaný, používaná instance StrongReferenceMessenger si na něj ponechá aktivní odkaz, což zabrání garbage collectoru, aby tuto instanci uvolnil. Můžete to buď provést ručně, nebo dědit z ObservableRecipient, která se ve výchozím nastavení automaticky postará o odebrání všech registrací zpráv příjemce při jeho deaktivaci (další informace o tom najdete v dokumentaci k ObservableRecipient).
K registraci obslužných rutin zpráv je také možné použít IRecipient<TMessage> rozhraní. V tomto případě bude muset každý příjemce implementovat rozhraní pro daný typ zprávy a poskytnout metodu Receive(TMessage) , která se vyvolá při příjmu zpráv, například:
// Create a message
public class MyRecipient : IRecipient<LoggedInUserChangedMessage>
{
public void Receive(LoggedInUserChangedMessage message)
{
// Handle the message here...
}
}
// Register that specific message...
WeakReferenceMessenger.Default.Register<LoggedInUserChangedMessage>(this);
// ...or alternatively, register all declared handlers
WeakReferenceMessenger.Default.RegisterAll(this);
// Send a message from some other module
WeakReferenceMessenger.Default.Send(new LoggedInUserChangedMessage(user));
Použití zpráv žádostí
Další užitečnou funkcí instancí messengeru je, že je možné je použít také k vyžádání hodnot z modulu do jiného. Aby to bylo možné provést, balíček obsahuje základní RequestMessage<T> třídu, která se dá použít takto:
// Create a message
public class LoggedInUserRequestMessage : RequestMessage<User>
{
}
// Register the receiver in a module
WeakReferenceMessenger.Default.Register<MyViewModel, LoggedInUserRequestMessage>(this, (r, m) =>
{
// Assume that "CurrentUser" is a private member in our viewmodel.
// As before, we're accessing it through the recipient passed as
// input to the handler, to avoid capturing "this" in the delegate.
m.Reply(r.CurrentUser);
});
// Request the value from another module
User user = WeakReferenceMessenger.Default.Send<LoggedInUserRequestMessage>();
Třída RequestMessage<T> obsahuje implicitní převodní operátor, který umožňuje převod z LoggedInUserRequestMessage na objekt User, který obsahuje. Tím také zkontrolujete, jestli byla pro zprávu přijata odpověď, a pokud tomu tak není, vyvolá se výjimka. Je také možné odesílat zprávy požadavku bez této povinné záruky odpovědi: stačí uložit vrácenou zprávu do místní proměnné a pak ručně zkontrolovat, jestli je hodnota odpovědi k dispozici nebo ne. Tím se automatická výjimka nespustí, pokud není přijata odpověď, když metoda Send vrátí výsledek.
Stejný obor názvů také obsahuje zprávu základních požadavků pro jiné scénáře: AsyncRequestMessage<T>CollectionRequestMessage<T> a AsyncCollectionRequestMessage<T>.
Tady je postup, jak můžete použít asynchronní zprávu žádosti:
// Create a message
public class LoggedInUserRequestMessage : AsyncRequestMessage<User>
{
}
// Register the receiver in a module
WeakReferenceMessenger.Default.Register<MyViewModel, LoggedInUserRequestMessage>(this, (r, m) =>
{
m.Reply(r.GetCurrentUserAsync()); // We're replying with a Task<User>
});
// Request the value from another module (we can directly await on the request)
User user = await WeakReferenceMessenger.Default.Send<LoggedInUserRequestMessage>();
Příklady
- Podívejte se na ukázkovou aplikaci (pro více architektur uživatelského rozhraní) a podívejte se na sadu nástrojů MVVM v akci.
- Další příklady najdete také v jednotkových testech.