Utusan
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:
IMessenger
, ,WeakReferenceMessenger
,StrongReferenceMessenger
IRecipient<TMessage>
,MessageHandler<TRecipient, TMessage>
,ObservableRecipient
,RequestMessage<T>
,AsyncRequestMessage<T>
, , .AsyncCollectionRequestMessage<T>
CollectionRequestMessage<T>
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
- Lihat contoh aplikasi (untuk beberapa kerangka kerja UI) untuk melihat Toolkit MVVM beraksi.
- Anda juga dapat menemukan lebih banyak contoh dalam pengujian unit.
MVVM Toolkit