Pada bulan Februari 2019,
ReactiveUI 9 , kerangka kerja lintas platform untuk membangun aplikasi GUI pada platform Microsoft .NET, dirilis.
ReactiveUI adalah alat untuk mengintegrasikan ekstensi reaktif dengan pola desain MVVM. Kenalan dengan kerangka kerja dapat dimulai dengan
serangkaian artikel tentang HabrΓ© atau
dari halaman depan dokumentasi . Pembaruan ReactiveUI 9 mencakup banyak
perbaikan dan peningkatan , tetapi mungkin perubahan yang paling menarik dan signifikan adalah
integrasi yang erat dengan kerangka kerja DynamicData , yang memungkinkan bekerja dengan mengubah koleksi dengan gaya reaktif. Mari kita coba mencari tahu dalam kasus apa
DynamicData dapat
berguna dan bagaimana kerangka reaktif yang kuat ini diatur di dalam!
Latar belakang
Pertama, kita mendefinisikan berbagai tugas yang
dipecahkan DynamicData dan mencari tahu mengapa alat standar untuk bekerja dengan mengubah set data dari
System.Collections.ObjectModel
namespace tidak cocok untuk kita.
Template MVVM, seperti yang Anda ketahui, melibatkan pembagian tanggung jawab antara lapisan model, presentasi, dan model presentasi aplikasi. Lapisan model diwakili oleh entitas domain dan layanan, dan tidak tahu apa-apa tentang model presentasi. Lapisan model merangkum seluruh logika aplikasi kompleks, dan model presentasi mendelegasikan operasi model, memberikan tampilan akses ke informasi tentang keadaan aplikasi saat ini melalui properti yang dapat diamati, perintah, dan koleksi. Alat standar untuk bekerja dengan mengubah properti adalah antarmuka
INotifyPropertyChanged
,
INotifyPropertyChanged
untuk bekerja dengan tindakan pengguna, dan
INotifyCollectionChanged
mengimplementasikan koleksi dan mengimplementasikan
ObservableCollection
dan
ReadOnlyObservableCollection
.

Implementasi
INotifyPropertyChanged
dan
ICommand
biasanya tetap pada hati nurani pengembang dan kerangka kerja MVVM yang digunakan, tetapi penggunaan
ObservableCollection
memberlakukan sejumlah batasan pada kami! Misalnya, kami tidak dapat mengubah koleksi dari utas latar belakang tanpa
Dispatcher.Invoke
Panggilan atau panggilan serupa, dan ini bisa berguna jika bekerja dengan array data yang beberapa operasi latar belakang disinkronkan dengan server. Perlu dicatat bahwa dalam MVVM idiomatik, lapisan model tidak perlu tahu tentang arsitektur aplikasi GUI yang digunakan, dan kompatibel dengan model dari MVC atau MVP, dan inilah sebabnya banyak
Dispatcher.Invoke
memungkinkan akses ke kontrol antarmuka pengguna dari latar belakang thread running dalam layanan domain, melanggar prinsip berbagi tanggung jawab antara lapisan aplikasi.
Tentu saja, dalam layanan domain akan dimungkinkan untuk mendeklarasikan suatu peristiwa, dan sebagai argumen dari suatu peristiwa, memberikan potongan dengan data yang diubah. Kemudian berlangganan acara tersebut, bungkus
Dispatcher.Invoke
Panggilan di antarmuka sehingga tidak tergantung pada kerangka GUI yang digunakan, pindah
Dispatcher.Invoke
model presentasi dan ubah
ObservableCollection
yang Dapat
ObservableCollection
kebutuhan, namun ada cara yang jauh lebih sederhana dan lebih elegan untuk menyelesaikan berbagai tugas yang ditunjukkan tanpa harus menulis sepeda . Ayo mulai belajar!
Ekstensi reaktif. Kelola aliran data
Untuk pemahaman lengkap tentang abstraksi yang diperkenalkan oleh
DynamicData dan prinsip-prinsip bekerja dengan mengubah dataset reaktif, mari kita ingat
apa itu pemrograman reaktif dan bagaimana menerapkannya dalam konteks platform Microsoft .NET dan pola desain MVVM . Cara untuk mengatur interaksi antar komponen program dapat bersifat interaktif dan reaktif. Dalam interaksi interaktif, fungsi konsumen secara sinkron menerima data dari fungsi penyedia (pendekatan berbasis-tarik,
T
,
IEnumerable
), dan dalam interaksi reaktif, fungsi konsumen secara tidak sinkron mengirimkan data ke fungsi konsumen (pendekatan berbasis-push,
Task
,
IObservable
).
Pemrograman reaktif adalah pemrograman menggunakan aliran data asinkron, dan ekstensi reaktif adalah kasus khusus dari implementasinya, berdasarkan pada
IObserver
dan
IObserver
dari namespace Sistem, yang mendefinisikan sejumlah operasi mirip LINQ pada antarmuka
IObservable
, yang disebut LINQ over Observable. Ekstensi reaktif mendukung .NET Standard dan berfungsi di mana pun platform Microsoft .NET berfungsi.

Kerangka kerja ReactiveUI mengundang pengembang aplikasi untuk mengambil keuntungan dari implementasi reaktif
ICommand
dan
INotifyPropertyChanged
, menyediakan alat yang kuat seperti
ReactiveCommand<TIn, TOut>
dan
WhenAnyValue
.
WhenAnyValue
memungkinkan
WhenAnyValue
untuk mengkonversi properti kelas yang mengimplementasikan INotifyPropertyChanged menjadi aliran peristiwa tipe
IObservable<T>
, yang menyederhanakan penerapan properti dependen.
public class ExampleViewModel : ReactiveObject { [Reactive]
ReactiveCommand<TIn, TOut>
memungkinkan Anda untuk bekerja dengan perintah tersebut, seperti kejadian tipe
IObservable<TOut>
, yang diterbitkan kapan pun perintah menyelesaikan eksekusi. Juga, perintah apa pun memiliki properti
IObservable<Exception>
tipe
IObservable<Exception>
.
Selama ini kami bekerja dengan
IObservable<T>
, seperti peristiwa yang menerbitkan nilai baru tipe
T
setiap kali keadaan objek yang dipantau berubah. Sederhananya,
IObservable<T>
adalah aliran peristiwa, urutan membentang dari waktu ke waktu.
Tentu saja, kami dapat dengan mudah dan alami bekerja dengan koleksi - setiap kali koleksi berubah, publikasikan koleksi baru dengan elemen yang diubah. Dalam hal ini, nilai yang dipublikasikan akan bertipe
IEnumerable<T>
atau lebih terspesialisasi, dan event itu sendiri akan bertipe
IObservable<IEnumerable<T>>
. Tetapi, seperti yang ditunjukkan oleh pembaca yang berpikir kritis, ini penuh dengan masalah serius dengan kinerja aplikasi, terutama jika tidak ada selusin elemen dalam koleksi kami, tetapi seratus, atau bahkan beberapa ribu!
Pengantar DynamicData
DynamicData adalah perpustakaan yang memungkinkan Anda menggunakan kekuatan penuh ekstensi reaktif saat bekerja dengan koleksi. Ekstensi reaktif di luar kotak tidak menyediakan cara optimal untuk bekerja dengan mengubah kumpulan data, dan
tugas DynamicData adalah memperbaikinya. Di sebagian besar aplikasi, ada kebutuhan untuk memperbarui koleksi secara dinamis - biasanya, koleksi diisi dengan beberapa elemen ketika aplikasi dimulai, dan kemudian diperbarui secara tidak sinkron, menyinkronkan informasi dengan server atau database. Aplikasi modern cukup kompleks, dan seringkali ada kebutuhan untuk membuat proyeksi koleksi - filter, ubah atau sortir elemen. DynamicData dirancang hanya untuk menghilangkan kode yang sangat rumit yang kita perlukan untuk mengelola set data yang berubah secara dinamis. Alat ini dikembangkan dan difinalisasi secara aktif, dan sekarang lebih dari 60 operator untuk bekerja dengan koleksi didukung.
DynamicData bukan merupakan implementasi alternatif dari
ObservableCollection<T>
. Arsitektur
DynamicData didasarkan terutama pada konsep-konsep pemrograman khusus domain. Ideologi penggunaan didasarkan pada fakta bahwa Anda mengelola beberapa sumber data, kumpulan yang dapat diakses oleh kode yang bertanggung jawab untuk menyinkronkan dan mengubah data. Selanjutnya, Anda menerapkan sejumlah operator ke sumber, yang dengannya Anda dapat mengubah data secara deklaratif, tanpa perlu secara manual membuat dan memodifikasi koleksi lainnya. Bahkan, dengan
DynamicData Anda memisahkan operasi baca dan tulis, dan Anda hanya bisa membaca dengan cara reaktif - karena itu, koleksi yang diwarisi akan selalu disinkronkan dengan sumbernya.
Alih-alih
IObservable<T>
klasik, DynamicData mendefinisikan operasi pada
IObservable<IChangeSet<T>>>
dan
IObservable<IChangeSet<TValue, TKey>>
, di mana
IChangeSet
adalah bongkahan berisi informasi tentang perubahan koleksi - jenis perubahan dan elemen yang terpengaruh. Pendekatan ini dapat secara signifikan meningkatkan kinerja kode untuk bekerja dengan koleksi yang ditulis dengan gaya reaktif. Pada saat yang sama,
IObservable<IChangeSet<T>>
selalu dapat diubah menjadi
IObservable<IEnumerable<T>>
biasa
IObservable<IEnumerable<T>>
jika menjadi perlu untuk memproses semua elemen koleksi sekaligus. Jika kedengarannya rumit - jangan khawatir, dari contoh kode semuanya akan menjadi jelas dan transparan!
Contoh DynamicData
Mari kita lihat serangkaian contoh untuk lebih memahami bagaimana DynamicData bekerja, perbedaannya dengan
System.Reactive
dan tugas apa yang dapat diselesaikan oleh pengembang perangkat lunak aplikasi biasa dengan GUI. Mari kita mulai dengan contoh komprehensif yang
diposting oleh DynamicData di GitHub . Dalam contoh, sumber data adalah
SourceCache<Trade, long>
, yang berisi kumpulan transaksi. Tugasnya adalah hanya menampilkan transaksi aktif, mengubah model menjadi objek proxy, mengurutkan koleksi.
Dalam contoh di atas, ketika Anda mengubah
SourceCache
, yang merupakan sumber data,
ReadOnlyObservableCollection
juga
ReadOnlyObservableCollection
berubah. Dalam hal ini, saat menghapus elemen dari koleksi, metode
Dispose
akan dipanggil, koleksi akan selalu diperbarui hanya dalam aliran GUI dan tetap diurutkan dan difilter. Keren, tidak ada
Dispatcher.Invoke
Kode
Dispatcher.Invoke
dan rumit!
SourceList dan Sumber Data SourceCache
DynamicData menyediakan dua koleksi khusus yang dapat digunakan sebagai sumber data yang bisa berubah. Koleksi ini adalah tipe
SourceList
dan
SourceCache<TObject, TKey>
. Disarankan untuk menggunakan
SourceCache
setiap kali
TObject
memiliki kunci unik, jika tidak gunakan
SourceList
. Objek-objek ini menyediakan .NET developer API untuk memodifikasi data -
Add
,
Remove
,
Insert
dan sejenisnya. Untuk mengonversi sumber data ke
IObservable<IChangeSet<T>>
atau
IObservable<IChangeSet<T, TKey>>
, gunakan operator
.Connect()
. Misalnya, jika Anda memiliki layanan yang memperbarui koleksi elemen di latar belakang, Anda dapat dengan mudah menyinkronkan daftar elemen-elemen ini dengan GUI, tanpa
Dispatcher.Invoke
dan ekses arsitektur:
public class BackgroundService : IBackgroundService {
DynamicData menggunakan tipe .NET bawaan untuk memetakan data ke dunia luar. Menggunakan operator DynamicData yang kuat, kita dapat mengubah
IObservable<IChangeSet<Trade>>
menjadi
ReadOnlyObservableCollection
model tampilan kami.
public class TradesViewModel : ReactiveObject { private readonly ReadOnlyObservableCollection<TradeVm> _trades; public ReadOnlyObservableCollection<TradeVm> Trades => _trades; public TradesViewModel(IBackgroundService background) {
Selain
Transform
,
Filter
dan
Sort
, DynamicData mencakup sejumlah operator lain, mendukung pengelompokan, operasi logis, perataan koleksi, menggunakan fungsi agregasi, tidak termasuk elemen identik, elemen penghitungan, dan bahkan virtualisasi pada level model representasi. Baca lebih lanjut tentang semua operator di
proyek README di GitHub .

Koleksi berulir tunggal dan ubah pelacakan
Selain
SourceList
dan
SourceCache
, pustaka DynamicData juga menyertakan implementasi single-threaded dari koleksi yang bisa diubah -
ObservableCollectionExtended
. Untuk menyinkronkan dua koleksi di model tampilan Anda, deklarasikan satu sebagai
ObservableCollectionExtended
dan yang lainnya sebagai
ReadOnlyObservableCollection
dan gunakan operator
ToObservableChangeSet
, yang berperilaku sama seperti
Connect
tetapi dirancang untuk bekerja dengan
ObservableCollection
.
DynamicData juga mendukung pelacakan perubahan di kelas yang mengimplementasikan antarmuka
INotifyPropertyChanged
. Misalnya, jika Anda ingin diberitahu tentang perubahan koleksi setiap kali properti item berubah, gunakan
AutoRefresh
dan berikan pemilih properti yang diinginkan dengan argumen.
AutoRefesh
dan operator DynamicData lainnya akan memungkinkan Anda untuk dengan mudah dan alami memvalidasi sejumlah besar formulir dan sub-formulir yang ditampilkan di layar!
Berdasarkan fungsionalitas DynamicData, Anda dapat dengan cepat membuat antarmuka yang cukup kompleks - ini terutama berlaku untuk sistem yang menampilkan sejumlah besar data waktu nyata, sistem pengiriman pesan instan, dan sistem pemantauan.

Kesimpulan
Ekstensi reaktif adalah alat yang ampuh yang memungkinkan Anda bekerja secara deklaratif dengan data dan antarmuka pengguna, menulis kode portabel dan didukung, dan memecahkan masalah rumit dengan cara yang sederhana dan elegan.
ReactiveUI memungkinkan pengembang .NET untuk secara erat mengintegrasikan ekstensi reaktif ke dalam proyek mereka menggunakan arsitektur MVVM dengan memberikan implementasi reaktif dari
INotifyPropertyChanged
dan
ICommand
, sementara
DynamicData menangani sinkronisasi pengumpulan dengan menerapkan
INotifyCollectionChanged
, memperluas kemampuan ekstensi reaktif dan menjaga kinerja.
Pustaka ReactiveUI dan
DynamicData kompatibel dengan kerangka kerja GUI paling populer dari platform .NET, termasuk Windows Presentation Foundation, Universal Windows Platform,
Avalonia , Xamarin. Android, Formulir Xamarin, Xamarin.iOS. Anda dapat mulai mempelajari DynamicData dari
halaman dokumentasi ReactiveUI yang sesuai . Pastikan juga untuk memeriksa proyek
DynamicData Snippets , yang berisi contoh penggunaan DynamicData untuk semua kesempatan.