Messenger

Gränssnittet IMessenger är ett kontrakt för typer som kan användas för att utbyta meddelanden mellan olika objekt. Detta kan vara användbart för att frikoppla olika moduler i ett program utan att behöva behålla starka referenser till typer som refereras. Det är också möjligt att skicka meddelanden till specifika kanaler, unikt identifierade av en token, och att ha olika budbärare i olika delar av ett program. MVVM Toolkit tillhandahåller två implementeringar direkt: WeakReferenceMessenger och StrongReferenceMessenger: den förra använder svaga referenser internt och erbjuder automatisk minneshantering för mottagare, medan den senare använder starka referenser och kräver att utvecklare manuellt avregistrerar sina mottagare när de inte längre behövs (mer information om hur du avregistrerar meddelandehanterare finns nedan), men i utbyte mot detta ger bättre prestanda och mycket mindre minnesanvändning.

Plattforms-API:er:IMessenger, WeakReferenceMessenger, StrongReferenceMessenger, IRecipient<TMessage>, MessageHandler<TRecipient, TMessage>, ObservableRecipient, RequestMessage<T>, AsyncRequestMessage<T>, CollectionRequestMessage<T>, AsyncCollectionRequestMessage<T>.

Så här fungerar det

Typer som implementerar IMessenger ansvarar för att upprätthålla länkar mellan mottagare (mottagare av meddelanden) och deras registrerade meddelandetyper, med relativa meddelandehanterare. Alla objekt kan registreras som mottagare för en viss meddelandetyp med hjälp av en meddelandehanterare, som anropas när instansen används för att skicka ett meddelande av den IMessenger typen. Det är också möjligt att skicka meddelanden via specifika kommunikationskanaler (var och en identifieras av en unik token), så att flera moduler kan utbyta meddelanden av samma typ utan att orsaka konflikter. Meddelanden som skickas utan token använder den delade standardkanalen.

Det finns två sätt att utföra meddelanderegistrering: antingen via IRecipient<TMessage> gränssnittet eller med hjälp av ett MessageHandler<TRecipient, TMessage> ombud som fungerar som meddelandehanterare. Med den första kan du registrera alla hanterare med ett enda anrop till RegisterAll tillägget, som automatiskt registrerar mottagarna för alla deklarerade meddelandehanterare, medan det senare är användbart när du behöver mer flexibilitet eller när du vill använda ett enkelt lambda-uttryck som meddelandehanterare.

Både WeakReferenceMessenger och StrongReferenceMessenger exponerar även en Default egenskap som erbjuder en trådsäker implementering inbyggd i paketet. Det är också möjligt att skapa flera messenger-instanser om det behövs, till exempel om en annan matas in med en DI-tjänstprovider i en annan modul i appen (till exempel flera fönster som körs i samma process).

Note

Eftersom typen WeakReferenceMessenger är enklare att använda och matchar beteendet för messenger-typen från MvvmLight biblioteket är det standardtypen som används av ObservableRecipient typen i MVVM Toolkit. StrongReferenceType Kan fortfarande användas genom att skicka en instans till konstruktorn för den klassen.

Skicka och ta emot meddelanden

Tänk på följande:

// 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));

Anta att den här meddelandetypen används i ett enkelt meddelandeprogram, som visar en rubrik med användarnamnet och profilbilden för den inloggade användaren, en panel med en lista över konversationer och en annan panel med meddelanden från den aktuella konversationen, om en är markerad. Anta att de här tre avsnitten stöds av typerna HeaderViewModel, ConversationsListViewModelConversationViewModel respektive . I det här scenariot kan LoggedInUserChangedMessage meddelandet skickas av HeaderViewModel efter att en inloggning har slutförts, och båda dessa andra viewmodels kan registrera hanterare för det. Till exempel ConversationsListViewModel läser in listan över konversationer för den nya användaren och ConversationViewModel stänger bara den aktuella konversationen, om en finns.

Instansen IMessenger tar hand om att leverera meddelanden till alla registrerade mottagare. Observera att en mottagare kan prenumerera på meddelanden av en viss typ. Observera att ärvda meddelandetyper inte är registrerade i standardimplementeringarna IMessenger som tillhandahålls av MVVM Toolkit.

När en mottagare inte längre behövs bör du avregistrera den så att den slutar ta emot meddelanden. Du kan avregistrera antingen efter meddelandetyp, registreringstoken eller efter mottagare:

// 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);

Varning

Som tidigare nämnts är detta inte absolut nödvändigt när du använder typen eftersom den WeakReferenceMessenger använder svaga referenser för att spåra mottagare, vilket innebär att oanvända mottagare fortfarande är berättigade till skräpinsamling även om de fortfarande har aktiva meddelandehanterare. Det är dock fortfarande bra att avbryta prenumerationen på dem för att förbättra föreställningarna. Å andra sidan använder implementeringen StrongReferenceMessenger starka referenser för att spåra de registrerade mottagarna. Detta görs av prestandaskäl och innebär att varje registrerad mottagare ska avregistreras manuellt för att undvika minnesläckor. Det vill säga, så länge en mottagare är registrerad kommer den StrongReferenceMessenger aktuella instansen att behålla en aktiv referens till den, vilket förhindrar att skräpsamlaren kan samla in den instansen. Du kan antingen hantera detta manuellt, eller så kan du ärva från ObservableRecipient, som som standard automatiskt tar hand om att ta bort alla meddelanderegistreringar för mottagaren när det inaktiveras (se dokument på ObservableRecipient för mer information om detta).

Det går också att använda IRecipient<TMessage> gränssnittet för att registrera meddelandehanterare. I det här fallet måste varje mottagare implementera gränssnittet för en viss meddelandetyp och ange en Receive(TMessage) metod som anropas när meddelanden tas emot, så här:

// 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));

Använda begärandemeddelanden

En annan användbar funktion i messenger-instanser är att de också kan användas för att begära värden från en modul till en annan. För att göra det innehåller paketet en basklass RequestMessage<T> som kan användas så här:

// 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>();

Klassen RequestMessage<T> innehåller en implicit konverterare som gör konverteringen från ett LoggedInUserRequestMessage till dess inneslutna User objekt möjlig. Detta kontrollerar också att ett svar har tagits emot för meddelandet och utlöser ett undantag om så inte är fallet. Det går också att skicka begärandemeddelanden utan den här obligatoriska svarsgarantin: lagra bara det returnerade meddelandet i en lokal variabel och kontrollera sedan manuellt om ett svarsvärde är tillgängligt eller inte. Om du gör det utlöses inte det automatiska undantaget om ett svar inte tas emot när Send metoden returneras.

Samma namnområde innehåller även meddelanden om basbegäranden för andra scenarier: AsyncRequestMessage<T>, CollectionRequestMessage<T> och AsyncCollectionRequestMessage<T>. Så här kan du använda ett asynkront meddelande om begäran:

// 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>();

Exempel

  • Kolla in exempelappen (för flera gränssnittsramverk) för att se MVVM Toolkit i praktiken.
  • Du kan också hitta fler exempel i enhetstesterna.