Sdílet prostřednictvím


Posel

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.

Rozhraní API platformy: , , , StrongReferenceMessengerIRecipient<TMessage>MessageHandler<TRecipient, TMessage>, , ObservableRecipient, RequestMessage<T>AsyncRequestMessage<T>, , . AsyncCollectionRequestMessage<T>CollectionRequestMessage<T>WeakReferenceMessengerIMessenger

Jak to funguje

Implementace IMessenger typů zodpovídá za udržování propojení mezi příjemci (příjemci zpráv) a jejich registrovanými typy zpráv s relativní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, jak provést registraci zpráv: buď prostřednictvím IRecipient<TMessage> rozhraní, nebo pomocí delegáta, který funguje jako obslužná rutina MessageHandler<TRecipient, TMessage> zprávy. 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.

A WeakReferenceMessenger StrongReferenceMessenger také vystavit Default vlastnost, která nabízí integrované implementace bezpečné pro přístup z více vláken do balíčku. V případě potřeby je také možné vytvořit více instancí messengeru, například pokud se do jiného zprostředkovatele služby DI vloží do jiného modulu aplikace (například několik 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. Lze StrongReferenceType jej 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 části jsou podporovány a HeaderViewModelConversationsListViewModel ConversationViewModel typy v uvedeném pořadí. V tomto scénáři LoggedInUserChangedMessage může být zpráva odeslána HeaderViewModel po dokončení operace přihlášení a oba tyto další modely zobrazení můžou 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 registrovány ve výchozích IMessenger implementacích poskytovaných 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);

Upozorňující

Jak už bylo zmíněno dříve, není to nezbytně nutné při použití WeakReferenceMessenger typu, protože používá slabé odkazy ke sledování příjemců, což znamená, že nepoužití příjemci budou mít stále nárok na uvolňování paměti, i když stále mají aktivní obslužné rutiny zpráv. 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 důvodů výkonu a znamená to, že každý registrovaný příjemce by měl být ručně neregistrovaný, aby nedošlo k nevracení paměti. To znamená, že pokud je příjemce zaregistrovaný, StrongReferenceMessenger zachová použitá instance aktivní odkaz, což zabrání tomu, aby systém uvolňování paměti mohl tuto instanci shromáždit. Můžete to zpracovat ručně nebo můžete dědit z ObservableRecipient, což se ve výchozím nastavení automaticky postará o odebrání všech registrací zpráv pro příjemce, když je deaktivován (další informace o tom najdete v ObservableRecipient dokumentaci).

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řevaděč, který umožňuje převod z objektu obsaženého LoggedInUserRequestMessage na jeho obsaženém User objektu. 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 neaktivuje automatická výjimka, pokud se při vrácení metody nepřijme Send odpověď.

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 testech jednotek.