Februari 2019 menandai pelepasan ReactiveUI 9 - kerangka kerja lintas-platform untuk membangun aplikasi GUI pada platform Microsoft .NET. ReactiveUI adalah alat untuk integrasi ketat ekstensi reaktif dengan pola desain MVVM. Anda dapat membiasakan diri dengan kerangka kerja melalui serangkaian video atau halaman pembuka dokumentasi . Pembaruan ReactiveUI 9 mencakup banyak perbaikan dan peningkatan , tetapi mungkin yang paling penting dan menarik adalah integrasi dengan kerangka kerja DynamicData , memungkinkan Anda untuk bekerja dengan koleksi dinamis dalam mode Reaktif. Mari cari tahu apa yang bisa kita gunakan untuk DynamicData dan bagaimana kerangka kerja reaktif yang kuat ini bekerja di bawah tenda!
Pendahuluan
Pertama-tama mari kita tentukan kasus penggunaan untuk DynamicData dan mencari tahu apa yang tidak kita sukai tentang alat default untuk bekerja dengan dataset dinamis dari System.Collections.ObjectModel
namespace.
Template MVVM, seperti yang kita ketahui, mengasumsikan pembagian tanggung jawab antara lapisan model, lapisan presentasi dan model presentasi aplikasi, juga dikenal sebagai model tampilan. Lapisan model diwakili oleh entitas domain dan layanan dan tidak tahu apa-apa tentang lapisan model tampilan. Model merangkum seluruh logika kompleks aplikasi, sementara model tampilan mendelegasikan operasi ke model, menyediakan akses ke informasi tentang keadaan aplikasi saat ini melalui properti yang dapat diamati, perintah, dan koleksi, ke tampilan. Alat default untuk bekerja dengan properti dinamis adalah antarmuka INotifyPropertyChanged
, untuk bekerja dengan tindakan pengguna - ICommand
, dan untuk bekerja dengan koleksi - antarmuka INotifyCollectionChanged
, serta implementasi seperti, sebagai ObservableCollection<T>
dan ReadOnlyObservableCollection<T>
.

Implementasi dari INotifyPropertyChanged
dan antarmuka ICommand
biasanya ICommand
pada pengembang dan kerangka kerja MVVM yang digunakan, tetapi menggunakan standar ObservableCollection<T>
membebankan sejumlah batasan! Sebagai contoh, kami tidak dapat mengubah koleksi dari utas latar belakang tanpa Dispatcher.Invoke
Panggilan atau panggilan serupa, dan itu akan sangat berguna untuk menyinkronkan array data dengan server melalui operasi latar belakang. Perlu dicatat, bahwa ketika menggunakan arsitektur MVVM yang bersih, lapisan model tidak boleh tahu apa-apa tentang kerangka kerja GUI yang digunakan, dan harus kompatibel dengan lapisan model dalam terminologi MVC atau MVP. Itu sebabnya banyak panggilan Dispatcher.Invoke
Panggilan dalam layanan domain melanggar prinsip segregasi tanggung jawab.
Tentu saja, kami dapat mendeklarasikan suatu peristiwa dalam layanan domain, dan mengirimkan potongan dengan item yang diubah sebagai argumen peristiwa, kemudian berlangganan acara tersebut, merangkum Dispatcher.Invoke
Menelepon memanggil balik antarmuka, sehingga aplikasi kami tidak akan bergantung pada GUI kerangka kerja, sebut antarmuka itu dari model tampilan dan modifikasi ObservableCollection<T>
sesuai, tetapi ada banyak cara yang lebih elegan untuk menangani masalah seperti itu tanpa perlu menemukan kembali roda. Apa yang kita tunggu?
Ekstensi reaktif. Mengelola Streaming Data yang Dapat Diamati
Untuk sepenuhnya memahami abstraksi yang diperkenalkan oleh DynamicData , dan cara bekerja dengan mengubah set data reaktif, mari kita ingat apa itu pemrograman reaktif dan bagaimana menggunakannya dalam konteks platform Microsoft .NET dan pola desain MVVM . Cara mengatur interaksi antar komponen program dapat bersifat interaktif atau reaktif. Dengan pendekatan interaktif, konsumen menerima data dari produsen secara serempak (berbasis pull, T, IEnumerable), dan dengan pendekatan reaktif, produsen mendorong data ke konsumen secara tidak sinkron (berbasis push, Tugas, IObservable).

Pemrograman reaktif adalah pemrograman dengan aliran data asinkron, dan ekstensi reaktif adalah implementasi pemrograman reaktif, berdasarkan pada antarmuka IObserver
dan IObserver
dari namespace System, yang mendefinisikan serangkaian operasi mirip LINQ pada antarmuka IObservable
, yang dikenal sebagai LINQ over Observable. Ekstensi reaktif mendukung .NET Standard dan berjalan di mana pun Microsoft .NET menjalankan.

ReactiveUI menawarkan pengembang aplikasi untuk mengambil keuntungan dari menggunakan implementasi reaktif untuk antarmuka ICommand
dan INotifyPropertyChanged
, dengan menyediakan alat-alat seperti ReactiveCommand<TIn, TOut>
dan WhenAnyValue
. WhenAnyValue
memungkinkan Anda untuk mengonversi properti kelas yang mengimplementasikan antarmuka INotifyPropertyChanged
ke aliran peristiwa tipe IObservable<T>
, ini menyederhanakan penerapan properti dependen.
public class ExampleViewModel : ReactiveObject { [Reactive]
ReactiveCommand<TIn, TOut>
memungkinkan Anda untuk bekerja dengan perintah seperti halnya dengan IObservable<TOut>
, yang diterbitkan kapan pun perintah menyelesaikan eksekusi. Juga, perintah apa pun memiliki properti IObservable<Exception>
tipe IObservable<Exception>
.
Hingga saat ini, kami telah bekerja dengan IObservable<T>
, seperti peristiwa yang menerbitkan nilai baru tipe T
setiap kali keadaan objek yang diamati berubah. Sederhananya, IObservable<T>
adalah aliran peristiwa, kumpulan tipe T
terbentang dalam waktu.
Tentu saja, kami dapat bekerja dengan koleksi dengan mudah dan alami - setiap kali koleksi berubah, kami dapat menerbitkan koleksi baru dengan elemen yang diubah. Dalam hal ini, nilai yang dipublikasikan akan bertipe IEnumerable<T>
atau lebih terspesialisasi, dan stream yang dapat diamati itu sendiri bertipe IObservable<IEnumerable<T>>
. Tetapi, seperti dicatat oleh pembaca yang berpikiran kritis, ini penuh dengan masalah kinerja kritis, 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 ekstensi reaktif saat bekerja dengan koleksi. Rx sangat kuat, tetapi di luar kotak tidak menyediakan apa pun untuk membantu mengelola koleksi, dan DynamicData memperbaikinya. Di sebagian besar aplikasi, ada kebutuhan untuk memperbarui koleksi secara dinamis - biasanya, koleksi diisi dengan item saat aplikasi dimulai, dan kemudian koleksi diperbarui secara tidak sinkron, menyinkronkan informasi dengan server atau database. Aplikasi modern cukup kompleks, dan seringkali perlu untuk membuat proyeksi koleksi - filter, transformasi, atau mengurutkan elemen. DynamicData dirancang untuk menghilangkan kode yang sangat rumit yang kita perlukan untuk mengelola set data yang berubah secara dinamis. Alat ini secara aktif mengembangkan dan memperbaiki, dan sekarang lebih dari 60 operator didukung untuk bekerja dengan koleksi.

DynamicData bukan merupakan implementasi alternatif dari ObservableCollection<T>
. Arsitektur DynamicData didasarkan terutama pada konsep pemrograman berbasis domain. Ideologi penggunaan didasarkan pada fakta bahwa Anda mengontrol sumber data tertentu, kumpulan kode yang bertanggung jawab untuk menyinkronkan dan bermutasi data memiliki akses. Selanjutnya, Anda menerapkan serangkaian operator ke sumber data, dengan bantuan operator tersebut 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 - oleh karena itu, koleksi yang diwarisi akan selalu tetap disinkronkan dengan sumbernya.
Alih-alih IObservable<T>
klasik IObservable<T>
, DynamicData mendefinisikan operasi pada IObservable<IChangeSet<T>>
dan IObservable<IChangeSet<TValue, TKey>>
, di mana IChangeSet
adalah bongkahan berisi informasi tentang perubahan koleksi, termasuk jenis perubahan dan elemen yang terpengaruh. Pendekatan ini dapat secara signifikan meningkatkan kinerja kode untuk bekerja dengan koleksi, ditulis secara reaktif. Anda selalu dapat mengubah IObservable<IChangeSet<T>>
menjadi IObservable<IEnumerable<T>>
, jika perlu mengakses semua elemen koleksi sekaligus. Jika ini terdengar sulit - jangan khawatir, contoh kode di bawah ini akan membuat semuanya jelas!
Data dinamis dalam aksi
Mari kita lihat beberapa contoh untuk lebih memahami bagaimana DynamicData bekerja, bagaimana ia berbeda dari System.Reactive dan tugas-tugas apa yang biasa diselesaikan oleh pengembang perangkat lunak GUI. Mari kita mulai dengan contoh komprehensif yang dipublikasikan di GitHub . Dalam contoh ini, sumber data adalah SourceCache<Trade, long>
berisi kumpulan transaksi. Tujuannya adalah hanya menampilkan transaksi aktif, mengubah model menjadi objek proxy, mengurutkan koleksi.
Dalam contoh di atas, ketika mengubah SourceCache
yang merupakan sumber data, ReadOnlyObservableCollection
juga berubah. Pada saat yang sama, ketika menghapus item dari koleksi, metode Dispose
akan dipanggil, koleksi akan selalu diperbarui hanya dari utas GUI dan akan tetap disortir dan disaring. Keren, sekarang kami tidak punya Dispatcher.Invoke
Panggilan telepon dan kode sederhana dan mudah dibaca!
Sumber Data. SourceList dan SourceCache
DynamicData menyediakan dua koleksi khusus yang dapat digunakan sebagai sumber data yang bisa berubah. Koleksi-koleksi ini adalah SourceList<TObject>
dan SourceCache<TObject, TKey>
. Disarankan untuk menggunakan SourceCache
setiap kali TObject
memiliki kunci unik, jika tidak gunakan SourceList
. Objek-objek ini menyediakan familiar untuk .NET developer API untuk manajemen koleksi - metode-metode seperti, Add
, Remove
, Insert
. Untuk mengonversi sumber data ke IObservable<IChangeSet<T>>
atau ke IObservable<IChangeSet<T, TKey>>
, gunakan operator .Connect()
. Misalnya, jika Anda memiliki layanan yang secara berkala memperbarui koleksi item di latar belakang, Anda dapat dengan mudah menyinkronkan daftar item-item ini dengan GUI, tanpa Dispatcher.Invoke
dan kode boilerplate serupa:
public class BackgroundService : IBackgroundService {
Dengan bantuan operator DynamicData yang kuat, kita dapat mengubah IObservable<IChangeSet<Trade>>
menjadi ReadOnlyObservableCollection
dideklarasikan dalam model tampilan kami.
public class TradesViewModel : ReactiveObject { private readonly ReadOnlyObservableCollection<TradeVm> _trades; public ReadOnlyObservableCollection<TradeVm> Trades => _trades; public TradesViewModel(IBackgroundService background) {
Selain operator Transform
, Filter
dan Sort
, DynamicData mendukung pengelompokan, operasi logis, perataan koleksi, penggunaan fungsi agregat, penghapusan elemen identik, penghitungan elemen, dan bahkan virtualisasi pada level model tampilan. Anda dapat membaca lebih lanjut tentang semua operator di README proyek di GitHub .

Selain dari SourceList
dan SourceCache
, pustaka DynamicData menyertakan implementasi koleksi yang dapat berulir tunggal - ObservableCollectionExtended
. Untuk menyinkronkan dua koleksi dalam model tampilan Anda, nyatakan salah satunya sebagai ObservableCollectionExtended
, dan yang lainnya sebagai ReadOnlyObservableCollection
, dan kemudian gunakan operator ToObservableChangeSet
, yang melakukan hal yang hampir sama dengan Connect, tetapi dimaksudkan untuk bekerja dengan ObservableCollection
.
DynamicData juga mendukung pelacakan perubahan di kelas yang mengimplementasikan antarmuka INotifyPropertyChanged
. Misalnya, jika Anda ingin menerima pemberitahuan setiap kali properti berubah, gunakan operator AutoRefresh
dan berikan pemilih properti yang diperlukan. AutoRefresh
dan operator DynamicData lainnya memungkinkan Anda untuk dengan mudah memvalidasi sejumlah besar formulir dan formulir bersarang yang ditampilkan di layar!
Anda dapat membuat UI kompleks menggunakan fungsionalitas DynamicData, dan ini sangat relevan untuk sistem yang menampilkan sejumlah besar data secara real time, seperti aplikasi pesan instan dan sistem pemantauan.

Kesimpulan
ReactiveX adalah alat yang ampuh yang memungkinkan Anda untuk bekerja dengan aliran acara dan dengan UI, menulis kode portabel dan dapat dipelihara dan menyelesaikan tugas-tugas kompleks dengan cara yang sederhana dan elegan. ReactiveUI memungkinkan para pengembang .NET untuk mengintegrasikan ekstensi reaktif ke dalam proyek mereka menggunakan arsitektur MVVM dengan implementasi reaktif dari INotifyPropertyChanged
dan ICommand
, sementara DynamicData menangani manajemen pengumpulan dengan menerapkan INotifyCollectionChanged
, memperluas kemampuan ekstensi reaktif dengan fokus pada kinerja.
Pustaka ReactiveUI dan DynamicData sepenuhnya kompatibel dengan semua kerangka kerja GUI pada platform .NET, termasuk Windows Presentation Foundation, Universal Windows Platform, Avalonia , Xamarin. Android, Formulir Xamarin, dan Xamarin iOS. Anda bisa mulai mempelajari DynamicData pada halaman yang sesuai dari dokumentasi ReactiveUI . Juga berhati-hatilah untuk membiasakan diri Anda dengan proyek Cuplikan DynamicData , yang berisi sampel kode untuk hampir semua yang Anda butuhkan.