Messenger

Antarmuka IMessenger adalah kontrak untuk jenis yang dapat digunakan untuk bertukar pesan antara objek yang berbeda. Ini dapat berguna untuk memisahkan modul aplikasi yang berbeda tanpa harus menyimpan referensi yang kuat untuk jenis yang direferensikan. Dimungkinkan juga untuk mengirim pesan ke saluran tertentu, diidentifikasi secara unik oleh token, dan memiliki messenger yang berbeda di berbagai bagian aplikasi. Toolkit MVVM menyediakan dua implementasi di luar kotak: WeakReferenceMessenger dan StrongReferenceMessenger: yang pertama menggunakan referensi lemah secara internal, menawarkan manajemen memori otomatis untuk penerima, sementara yang terakhir menggunakan referensi yang kuat dan mengharuskan pengembang untuk secara manual berhenti berlangganan penerima mereka ketika mereka tidak lagi diperlukan (detail lebih lanjut tentang cara membatalkan pendaftaran penangan pesan dapat ditemukan di bawah), tetapi sebagai gantinya menawarkan performa yang lebih baik dan penggunaan memori yang jauh lebih sedikit.

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

Cara kerjanya

Jenis penerapan IMessenger bertanggung jawab untuk mempertahankan tautan antara penerima (penerima pesan) dan jenis pesan terdaftar mereka, dengan penangan pesan relatif. Objek apa pun dapat didaftarkan sebagai penerima untuk jenis pesan tertentu menggunakan penangan pesan, yang akan dipanggil setiap kali instans digunakan untuk mengirim pesan jenis tersebut IMessenger . Dimungkinkan juga untuk mengirim pesan melalui saluran komunikasi tertentu (masing-masing diidentifikasi oleh token unik), sehingga beberapa modul dapat bertukar pesan dengan jenis yang sama tanpa menyebabkan konflik. Pesan yang dikirim tanpa token menggunakan saluran bersama default.

Ada dua cara untuk melakukan pendaftaran pesan: baik melalui IRecipient<TMessage> antarmuka, atau menggunakan delegasi yang MessageHandler<TRecipient, TMessage> bertindak sebagai penangan pesan. Yang pertama memungkinkan Anda mendaftarkan semua handler dengan satu panggilan ke RegisterAll ekstensi, yang secara otomatis mendaftarkan penerima semua handler pesan yang dideklarasikan, sementara yang terakhir berguna ketika Anda membutuhkan lebih banyak fleksibilitas atau ketika Anda ingin menggunakan ekspresi lambda sederhana sebagai handler pesan.

Baik WeakReferenceMessenger dan StrongReferenceMessenger juga mengekspos Default properti yang menawarkan implementasi aman utas bawaan ke dalam paket. Dimungkinkan juga untuk membuat beberapa instans messenger jika diperlukan, misalnya jika yang berbeda disuntikkan dengan penyedia layanan DI ke dalam modul aplikasi yang berbeda (misalnya, beberapa jendela yang berjalan dalam proses yang sama).

Catatan

WeakReferenceMessenger Karena jenisnya lebih sederhana untuk digunakan dan cocok dengan perilaku jenis messenger dari MvvmLight pustaka, ini adalah jenis default yang digunakan oleh ObservableRecipient jenis di Toolkit MVVM. StrongReferenceType masih dapat digunakan, dengan meneruskan instans ke konstruktor kelas tersebut.

Mengirim dan menerima pesan

Pertimbangkan hal berikut:

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

Mari kita bayangkan jenis pesan ini digunakan dalam aplikasi olahpesan sederhana, yang menampilkan header dengan nama pengguna dan gambar profil pengguna yang saat ini dicatat, panel dengan daftar percakapan, dan panel lain dengan pesan dari percakapan saat ini, jika dipilih. Katakanlah ketiga bagian ini masing-masing didukung oleh HeaderViewModel, ConversationsListViewModel dan ConversationViewModel jenis. Dalam skenario ini, LoggedInUserChangedMessage pesan mungkin dikirim oleh HeaderViewModel setelah operasi masuk selesai, dan kedua viewmodel lainnya mungkin mendaftarkan handler untuk itu. Misalnya, ConversationsListViewModel akan memuat daftar percakapan untuk pengguna baru, dan ConversationViewModel hanya akan menutup percakapan saat ini, jika ada.

IMessenger Instans mengurus pengiriman pesan ke semua penerima terdaftar. Perhatikan bahwa penerima dapat berlangganan pesan dengan jenis tertentu. Perhatikan bahwa jenis pesan yang diwariskan tidak terdaftar dalam implementasi default IMessenger yang disediakan oleh Toolkit MVVM.

Ketika penerima tidak diperlukan lagi, Anda harus membatalkan pendaftarannya sehingga akan berhenti menerima pesan. Anda dapat membatalkan pendaftaran baik berdasarkan jenis pesan, berdasarkan token pendaftaran, atau oleh penerima:

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

Peringatan

Seperti disebutkan sebelumnya, ini tidak benar-benar diperlukan saat menggunakan WeakReferenceMessenger jenis , karena menggunakan referensi lemah untuk melacak penerima, yang berarti bahwa penerima yang tidak digunakan masih akan memenuhi syarat untuk pengumpulan sampah meskipun mereka masih memiliki penangan pesan aktif. Ini masih merupakan praktik yang baik untuk berhenti berlangganan mereka sekalipun, untuk meningkatkan performa. Di sisi lain, StrongReferenceMessenger implementasi menggunakan referensi yang kuat untuk melacak penerima terdaftar. Ini dilakukan untuk alasan performa, dan itu berarti bahwa setiap penerima terdaftar harus secara manual tidak terdaftar untuk menghindari kebocoran memori. Artinya, selama penerima terdaftar, StrongReferenceMessenger instans yang digunakan akan menyimpan referensi aktif ke dalamnya, yang akan mencegah pengumpul sampah dapat mengumpulkan instans tersebut. Anda dapat menangani ini secara manual, atau Anda dapat mewarisi dari ObservableRecipient, yang secara default secara otomatis menangani penghapusan semua pendaftaran pesan untuk penerima ketika dinonaktifkan (lihat dokumen di ObservableRecipient untuk informasi selengkapnya tentang ini).

Dimungkinkan IRecipient<TMessage> juga untuk menggunakan antarmuka untuk mendaftarkan penangan pesan. Dalam hal ini, setiap penerima perlu menerapkan antarmuka untuk jenis pesan tertentu, dan menyediakan Receive(TMessage) metode yang akan dipanggil saat menerima pesan, seperti:

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

Menggunakan pesan permintaan

Fitur berguna lain dari instans messenger adalah mereka juga dapat digunakan untuk meminta nilai dari modul ke modul lainnya. Untuk melakukannya, paket mencakup kelas dasar RequestMessage<T> , yang dapat digunakan seperti itu:

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

Kelas RequestMessage<T> ini mencakup pengonversi implisit yang memungkinkan konversi dari ke LoggedInUserRequestMessage objek yang terkandung User . Ini juga akan memeriksa bahwa respons telah diterima untuk pesan, dan melemparkan pengecualian jika itu tidak terjadi. Dimungkinkan juga untuk mengirim pesan permintaan tanpa jaminan respons wajib ini: cukup simpan pesan yang dikembalikan dalam variabel lokal, lalu periksa secara manual apakah nilai respons tersedia atau tidak. Melakukannya tidak akan memicu pengecualian otomatis jika respons tidak diterima saat Send metode kembali.

Namespace yang sama juga menyertakan pesan permintaan dasar untuk skenario lain: AsyncRequestMessage<T>, CollectionRequestMessage<T> dan AsyncCollectionRequestMessage<T>. Berikut cara menggunakan pesan permintaan asinkron:

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

Contoh