Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
De IMessenger interface is een contract voor typen die kunnen worden gebruikt voor het uitwisselen van berichten tussen verschillende objecten. Dit kan handig zijn om verschillende modules van een toepassing los te koppelen zonder sterke verwijzingen naar typen te hoeven behouden. Het is ook mogelijk om berichten te verzenden naar specifieke kanalen, uniek geïdentificeerd door een token en om verschillende messengers in verschillende secties van een toepassing te hebben. De MVVM Toolkit biedt standaard twee implementaties: WeakReferenceMessenger en StrongReferenceMessenger: de eerste maakt intern gebruik van zwakke verwijzingen en biedt automatisch geheugenbeheer voor ontvangers, terwijl de tweede sterke verwijzingen gebruikt en vereist dat ontwikkelaars de registratie van hun ontvangers handmatig ongedaan maken wanneer deze niet langer nodig zijn (meer informatie over het afmelden van berichtverwerkers vindt u hieronder), maar in ruil daarvoor betere prestaties en een veel lager geheugengebruik biedt.
Platform-API’s:
IMessenger,WeakReferenceMessenger,StrongReferenceMessenger,IRecipient<TMessage>,MessageHandler<TRecipient, TMessage>,ObservableRecipient,RequestMessage<T>,AsyncRequestMessage<T>,CollectionRequestMessage<T>,AsyncCollectionRequestMessage<T>.
Hoe werkt het?
Typen die IMessenger implementeren, zijn verantwoordelijk voor het in stand houden van koppelingen tussen ontvangers van berichten en hun geregistreerde berichttypen, met de bijbehorende berichtverwerkers. Elk object kan worden geregistreerd als geadresseerde voor een bepaald berichttype met behulp van een berichthandler, die wordt aangeroepen wanneer het IMessenger exemplaar wordt gebruikt om een bericht van dat type te verzenden. Het is ook mogelijk om berichten te verzenden via specifieke communicatiekanalen (elk geïdentificeerd door een uniek token), zodat meerdere modules berichten van hetzelfde type kunnen uitwisselen zonder conflicten te veroorzaken. Berichten die zonder een token worden verzonden, gebruiken het standaard gedeelde kanaal.
Er zijn twee manieren om berichtregistratie uit te voeren: via de IRecipient<TMessage> interface of met behulp van een MessageHandler<TRecipient, TMessage> gemachtigde die fungeert als berichthandler. Met de eerste stap kunt u alle handlers registreren met één aanroep naar de RegisterAll extensie, waarmee automatisch de geadresseerden van alle gedeclareerde berichthandlers worden geregistreerd, terwijl de laatste handig is wanneer u meer flexibiliteit nodig hebt of wanneer u een eenvoudige lambda-expressie wilt gebruiken als berichthandler.
Beide WeakReferenceMessenger en StrongReferenceMessenger maken ook een Default eigenschap beschikbaar die een thread-veilige implementatie biedt ingebouwd in het pakket. Het is ook mogelijk om indien nodig meerdere messenger-exemplaren te maken, bijvoorbeeld als een andere wordt geïnjecteerd met een DI-serviceprovider in een andere module van de app (bijvoorbeeld meerdere vensters die in hetzelfde proces worden uitgevoerd).
Note
Omdat het WeakReferenceMessenger type eenvoudiger te gebruiken is en overeenkomt met het gedrag van het messenger-type uit de MvvmLight bibliotheek, is het het standaardtype dat wordt gebruikt door het ObservableRecipient type in de MVVM Toolkit. De StrongReferenceType kan nog steeds worden gebruikt door een exemplaar door te geven aan de constructor van die klasse.
Berichten verzenden en ontvangen
Houd rekening met het volgende:
// 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));
Stel dat dit berichttype wordt gebruikt in een eenvoudige berichtentoepassing, waarin een koptekst wordt weergegeven met de gebruikersnaam en profielafbeelding van de momenteel aangemelde gebruiker, een deelvenster met een lijst met gesprekken en een ander deelvenster met berichten uit het huidige gesprek, indien geselecteerd. Stel dat deze drie secties respectievelijk worden ondersteund door de typen HeaderViewModel, ConversationsListViewModel en ConversationViewModel. In dit scenario kan het LoggedInUserChangedMessage-bericht door de HeaderViewModel worden verzonden nadat een aanmeldingsbewerking is voltooid, en kunnen beide andere viewmodels hiervoor afhandelaars registreren. Laadt bijvoorbeeld ConversationsListViewModel de lijst met gesprekken voor de nieuwe gebruiker en ConversationViewModel sluit gewoon het huidige gesprek, indien aanwezig.
De IMessenger instantie zorgt voor de aflevering van berichten aan alle geregistreerde ontvangers. Een geadresseerde kan zich abonneren op berichten van een specifiek type. Houd er rekening mee dat overgenomen berichttypen niet zijn geregistreerd in de standaard IMessenger implementaties van de MVVM Toolkit.
Wanneer een geadresseerde niet meer nodig is, moet u de registratie ongedaan maken, zodat deze geen berichten meer ontvangt. U kunt de registratie opheffen op berichttype, op registratietoken of op geadresseerde:
// 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);
Warning
Zoals eerder vermeld, is dit niet strikt noodzakelijk bij gebruik van het WeakReferenceMessenger-type, omdat dit zwakke verwijzingen gebruikt om ontvangers bij te houden. Dat betekent dat ongebruikte ontvangers nog steeds door de garbage collector kunnen worden opgeruimd, ook al hebben ze nog steeds actieve handlers voor berichten. Het is echter nog steeds een goede gewoonte om ze af te melden, om de prestaties te verbeteren. Aan de andere kant gebruikt de StrongReferenceMessenger implementatie sterke verwijzingen om de geregistreerde ontvangers bij te houden. Dit gebeurt om prestatieredenen en betekent dat elke geregistreerde geadresseerde handmatig de registratie ongedaan moet maken om geheugenlekken te voorkomen. Dat wil zeggen: zolang een ontvanger is geregistreerd, blijft de gebruikte StrongReferenceMessenger-instantie er een actieve verwijzing naar behouden, waardoor de garbagecollector die instantie niet kan opruimen. U kunt dit handmatig afhandelen, of u kunt overnemen van ObservableRecipient, die standaard automatisch zorgt voor het verwijderen van alle berichtregistraties voor geadresseerden wanneer deze is gedeactiveerd (zie de documenten ObservableRecipient voor meer informatie hierover).
Het is ook mogelijk om de IRecipient<TMessage> interface te gebruiken om berichthandlers te registreren. In dit geval moet elke geadresseerde de interface voor een bepaald berichttype implementeren en een Receive(TMessage) methode opgeven die wordt aangeroepen bij het ontvangen van berichten, zoals:
// 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));
Aanvraagberichten gebruiken
Een andere handige functie van messenger-exemplaren is dat ze ook kunnen worden gebruikt om waarden van een module naar een andere aan te vragen. Om dit te doen, bevat het pakket een basisklasse RequestMessage<T> , die als volgt kan worden gebruikt:
// 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>();
De RequestMessage<T> klasse bevat een impliciet conversieprogramma dat de conversie van een LoggedInUserRequestMessage naar het ingesloten User object mogelijk maakt. Hiermee wordt ook gecontroleerd of er een antwoord voor het bericht is ontvangen en wordt er een uitzondering gegenereerd als dat niet het geval is. Het is ook mogelijk om aanvraagberichten te verzenden zonder deze verplichte antwoordgarantie: sla gewoon het geretourneerde bericht op in een lokale variabele en controleer vervolgens handmatig of een antwoordwaarde beschikbaar is of niet. Als u dit doet, wordt de automatische uitzondering niet geactiveerd als er geen antwoord wordt ontvangen wanneer de Send methode wordt geretourneerd.
Dezelfde naamruimte bevat ook een bericht met basisaanvragen voor andere scenario's: AsyncRequestMessage<T>en CollectionRequestMessage<T>AsyncCollectionRequestMessage<T>.
U kunt als volgt een asynchroon aanvraagbericht gebruiken:
// 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>();
Examples
- Bekijk de voorbeeld-app (voor meerdere UI-frameworks) om de MVVM Toolkit in actie te zien.
- U vindt ook meer voorbeelden in de eenheidstests.