Arsitektur WPF
Topik ini menyediakan tur berpemandu dari hierarki kelas Windows Presentation Foundation (WPF). Ini mencakup sebagian besar subsistem utama WPF, dan menjelaskan bagaimana mereka berinteraksi. Ini juga merinci beberapa pilihan yang dibuat oleh arsitek WPF.
System.Object
Model pemrograman WPF utama diekspos melalui kode terkelola. Awal fase desain WPF ada sejumlah perdebatan tentang di mana garis harus digambar antara komponen terkelola sistem dan yang tidak dikelola. CLR menyediakan sejumlah fitur yang membuat pengembangan lebih produktif dan kuat (termasuk manajemen memori, penanganan kesalahan, sistem jenis umum, dll.) tetapi mereka dikenakan biaya.
Komponen utama WPF diilustrasikan pada gambar di bawah ini. Bagian merah dari diagram (PresentationFramework, PresentationCore, dan milcore) adalah bagian kode utama WPF. Dari jumlah tersebut, hanya satu yang merupakan komponen yang tidak dikelola – milcore. Milcore ditulis dalam kode yang tidak dikelola untuk mengaktifkan integrasi yang ketat dengan DirectX. Semua tampilan di WPF dilakukan melalui mesin DirectX, memungkinkan penyajian perangkat keras dan perangkat lunak yang efisien. WPF juga memerlukan kontrol yang baik atas memori dan eksekusi. Mesin komposisi dalam milcore sangat sensitif terhadap performa, dan diperlukan untuk memberikan banyak keuntungan dari CLR untuk mendapatkan performa.
Komunikasi antara bagian WPF yang dikelola dan tidak dikelola dibahas nanti dalam topik ini. Sisa model pemrograman terkelola dijelaskan di bawah ini.
System.Threading.DispatcherObject
Sebagian besar objek dalam WPF berasal dari DispatcherObject, yang menyediakan konstruksi dasar untuk menangani konkurensi dan utas. WPF didasarkan pada sistem olahpesan yang diterapkan oleh dispatcher. Ini berfungsi seperti pompa pesan Win32 yang akrab; bahkan, dispatcher WPF menggunakan pesan User32 untuk melakukan panggilan lintas utas.
Benar-benar ada dua konsep inti yang perlu dipahami ketika membahas konkurensi di WPF - dispatcher dan afinitas utas.
Selama fase desain WPF, tujuannya adalah untuk pindah ke satu utas eksekusi, tetapi model "afinitas" non-utas. Afinitas utas terjadi ketika komponen menggunakan identitas utas yang dieksekusi untuk menyimpan beberapa jenis status. Bentuk yang paling umum dari ini adalah menggunakan penyimpanan lokal utas (TLS) untuk menyimpan status. Afinitas utas mengharuskan setiap utas logis eksekusi hanya dimiliki oleh satu utas fisik dalam sistem operasi, yang dapat menjadi intensif memori. Pada akhirnya, model utas WPF tetap sinkron dengan model utas User32 yang ada dari eksekusi utas tunggal dengan afinitas utas. Alasan utama untuk ini adalah interoperabilitas – sistem seperti OLE 2.0, clipboard, dan Internet Explorer semuanya memerlukan eksekusi afinitas utas tunggal (STA).
Mengingat bahwa Anda memiliki objek dengan utas STA, Anda memerlukan cara untuk berkomunikasi antara utas, dan memvalidasi bahwa Anda berada di utas yang benar. Di sini terletak peran dispatcher. Dispatcher adalah sistem pengiriman pesan dasar, dengan beberapa antrean yang diprioritaskan. Contoh pesan termasuk pemberitahuan input mentah (mouse dipindahkan), fungsi kerangka kerja (tata letak), atau perintah pengguna (jalankan metode ini). Dengan turunan dari DispatcherObject, Anda membuat objek CLR yang memiliki perilaku STA, dan akan diberikan penunjuk ke dispatcher pada waktu pembuatan.
System.Windows.DependencyObject
Salah satu filosofi arsitektur utama yang digunakan dalam membangun WPF adalah preferensi untuk properti atas metode atau peristiwa. Properti bersifat deklaratif dan memungkinkan Anda untuk lebih mudah menentukan niat alih-alih tindakan. Ini juga mendukung berbasis model, atau berbasis data, sistem untuk menampilkan konten antarmuka pengguna. Filosofi ini memiliki efek yang dimaksudkan untuk membuat lebih banyak properti yang dapat Anda ikat, untuk mengontrol perilaku aplikasi dengan lebih baik.
Untuk memiliki lebih banyak sistem yang didorong oleh properti, sistem properti yang lebih kaya daripada apa yang disediakan CLR diperlukan. Contoh sederhana dari kekayaan ini adalah pemberitahuan perubahan. Untuk mengaktifkan pengikatan dua arah, Anda memerlukan kedua sisi ikatan untuk mendukung pemberitahuan perubahan. Agar perilaku terikat dengan nilai properti, Anda perlu diberi tahu saat nilai properti berubah. Microsoft .NET Framework memiliki antarmuka, INotifyPropertyChange, yang memungkinkan objek untuk menerbitkan pemberitahuan perubahan, namun bersifat opsional.
WPF menyediakan sistem properti yang lebih kaya, berasal dari jenisnya DependencyObject . Sistem properti benar-benar merupakan sistem properti "dependensi" karena melacak dependensi antara ekspresi properti dan secara otomatis memvalidasi ulang nilai properti ketika dependensi berubah. Misalnya, jika Anda memiliki properti yang mewarisi (seperti FontSize), sistem secara otomatis diperbarui jika properti berubah pada induk elemen yang mewarisi nilai.
Fondasi sistem properti WPF adalah konsep ekspresi properti. Dalam rilis pertama WPF ini, sistem ekspresi properti ditutup, dan ekspresi semuanya disediakan sebagai bagian dari kerangka kerja. Ekspresi adalah mengapa sistem properti tidak memiliki pengikatan data, gaya, atau warisan yang dikodekan secara permanen, melainkan disediakan oleh lapisan selanjutnya dalam kerangka kerja.
Sistem properti juga menyediakan penyimpanan nilai properti yang jarang. Karena objek dapat memiliki lusinan (jika bukan ratusan) properti, dan sebagian besar nilai berada dalam status defaultnya (diwariskan, diatur oleh gaya, dll.), tidak setiap instans objek perlu memiliki bobot penuh dari setiap properti yang ditentukan di atasnya.
Fitur baru akhir dari sistem properti adalah gagasan properti terlampir. Elemen WPF dibangun berdasarkan prinsip komposisi dan penggunaan kembali komponen. Sering kali beberapa elemen yang berisi (seperti Grid elemen tata letak) membutuhkan data tambahan pada elemen anak untuk mengontrol perilakunya (seperti informasi Baris/Kolom). Alih-alih mengaitkan semua properti ini dengan setiap elemen, objek apa pun diizinkan untuk memberikan definisi properti untuk objek lain. Ini mirip dengan fitur "expando" JavaScript.
System.Windows.Media.Visual
Dengan sistem yang ditentukan, langkah selanjutnya adalah membuat piksel digambar ke layar. Kelas Visual ini menyediakan untuk membangun pohon objek visual, masing-masing secara opsional berisi instruksi gambar dan metadata tentang cara merender instruksi tersebut (kliping, transformasi, dll.). Visual dirancang agar sangat ringan dan fleksibel, sehingga sebagian besar fitur tidak memiliki paparan API publik dan sangat bergantung pada fungsi panggilan balik yang dilindungi.
Visual benar-benar titik masuk ke sistem komposisi WPF. Visual adalah titik koneksi antara kedua subsistem ini, API terkelola dan milcore yang tidak dikelola.
WPF menampilkan data dengan melintasi struktur data yang tidak dikelola yang dikelola oleh milcore. Struktur ini, yang disebut node komposisi, mewakili pohon tampilan hierarkis dengan instruksi penyajian di setiap simpul. Pohon ini, yang diilustrasikan di sisi kanan gambar di bawah ini, hanya dapat diakses melalui protokol olahpesan.
Saat memprogram WPF, Anda membuat Visual elemen, dan jenis turunan, yang secara internal berkomunikasi dengan pohon komposisi melalui protokol olahpesan ini. Masing-masing Visual dalam WPF dapat membuat satu, tidak ada, atau beberapa node komposisi.
Ada detail arsitektur yang sangat penting untuk diperhatikan di sini - seluruh pohon visual dan instruksi menggambar di-cache. Dalam istilah grafis, WPF menggunakan sistem penyajian yang dipertahankan. Ini memungkinkan sistem untuk mengecat ulang pada kecepatan refresh tinggi tanpa sistem komposisi memblokir panggilan balik ke kode pengguna. Ini membantu mencegah munculnya aplikasi yang tidak responsif.
Detail penting lainnya yang tidak benar-benar terlihat dalam diagram adalah bagaimana sistem benar-benar melakukan komposisi.
Di User32 dan GDI, sistem bekerja pada sistem kliping mode langsung. Ketika komponen perlu dirender, sistem menetapkan batas kliping di luar mana komponen tidak diizinkan untuk menyentuh piksel, dan kemudian komponen diminta untuk melukis piksel dalam kotak itu. Sistem ini bekerja sangat baik dalam sistem yang dibatasi memori karena ketika sesuatu berubah, Anda hanya perlu menyentuh komponen yang terpengaruh - tidak ada dua komponen yang pernah berkontribusi pada warna satu piksel.
WPF menggunakan model lukisan "algoritma pelukis". Ini berarti bahwa alih-alih mengklip setiap komponen, setiap komponen diminta untuk merender dari belakang ke depan layar. Ini memungkinkan setiap komponen untuk melukis di atas tampilan komponen sebelumnya. Keuntungan dari model ini adalah Anda dapat memiliki bentuk yang kompleks dan sebagian transparan. Dengan perangkat keras grafis modern saat ini, model ini relatif cepat (yang tidak terjadi ketika User32/ GDI dibuat).
Seperti disebutkan sebelumnya, filosofi inti WPF adalah pindah ke model pemrograman yang lebih deklaratif dan "berpusat pada properti". Dalam sistem visual, ini muncul di beberapa tempat menarik.
Pertama, jika Anda memikirkan sistem grafis mode yang dipertahankan, ini benar-benar menjauh dari model jenis DrawLine/DrawLine yang imperatif, ke model berorientasi data – Line()/new Line() baru. Perpindahan ke penyajian berbasis data ini memungkinkan operasi kompleks pada instruksi menggambar untuk diekspresikan menggunakan properti. Jenis yang berasal dari Drawing secara efektif adalah model objek untuk penyajian.
Kedua, jika Anda mengevaluasi sistem animasi, Anda akan melihat bahwa itu hampir sepenuhnya deklaratif. Alih-alih mengharuskan pengembang untuk menghitung lokasi berikutnya, atau warna berikutnya, Anda dapat mengekspresikan animasi sebagai sekumpulan properti pada objek animasi. Animasi ini kemudian dapat mengekspresikan niat pengembang atau desainer (memindahkan tombol ini dari sini ke sana dalam 5 detik), dan sistem dapat menentukan cara paling efisien untuk mencapainya.
System.Windows.UIElement
UIElement menentukan subsistem inti termasuk Tata Letak, Input, dan Peristiwa.
Tata letak adalah konsep inti dalam WPF. Dalam banyak sistem ada sekumpulan model tata letak tetap (HTML mendukung tiga model untuk tata letak; aliran, absolut, dan tabel) atau tidak ada model untuk tata letak (User32 benar-benar hanya mendukung posisi absolut). WPF dimulai dengan asumsi bahwa pengembang dan desainer menginginkan model tata letak yang fleksibel dan dapat diperluas, yang dapat didorong oleh nilai properti daripada logika imperatif. Pada tingkat , UIElement kontrak dasar untuk tata letak diperkenalkan - model dua fase dengan Measure dan Arrange lulus.
Measure memungkinkan komponen untuk menentukan berapa banyak ukuran yang ingin diambil. Ini adalah fase terpisah dari Arrange karena ada banyak situasi di mana elemen induk akan meminta anak untuk mengukur beberapa kali untuk menentukan posisi dan ukuran optimalnya. Fakta bahwa elemen induk meminta elemen turunan untuk mengukur menunjukkan filosofi kunci lain dari WPF – ukuran ke konten. Semua kontrol dalam WPF mendukung kemampuan untuk mengukur ukuran hingga ukuran alami kontennya. Ini membuat pelokalan jauh lebih mudah, dan memungkinkan tata letak elemen dinamis saat hal-hal mengubah ukuran. Fase ini Arrange memungkinkan induk untuk memposisikan dan menentukan ukuran akhir setiap anak.
Banyak waktu sering dihabiskan berbicara tentang sisi output WPF - Visual dan objek terkait. Namun ada sejumlah besar inovasi di sisi input juga. Mungkin perubahan paling mendasar dalam model input untuk WPF adalah kontras mode tenda l tempat peristiwa input dirutekan melalui sistem.
Input berasal sebagai sinyal pada driver perangkat mode kernel dan dirutekan ke proses dan utas yang benar melalui proses rumit yang melibatkan kernel Windows dan User32. Setelah pesan User32 yang sesuai dengan input dirutekan ke WPF, pesan tersebut dikonversi menjadi pesan input mentah WPF dan dikirim ke dispatcher. WPF memungkinkan peristiwa input mentah dikonversi ke beberapa peristiwa aktual, memungkinkan fitur seperti "MouseEnter" diterapkan pada tingkat sistem yang rendah dengan pengiriman yang dijamin.
Setiap peristiwa input dikonversi menjadi setidaknya dua peristiwa – peristiwa "pratinjau" dan peristiwa aktual. Semua peristiwa di WPF memiliki gagasan perutean melalui pohon elemen. Peristiwa dikatakan "gelembung" jika melintasi dari target ke atas pohon ke akar, dan dikatakan "terowongan" jika dimulai dari akar dan melintasi ke target. Input terowongan peristiwa pratinjau, memungkinkan elemen apa pun di pohon kesempatan untuk memfilter atau mengambil tindakan pada peristiwa. Peristiwa reguler (non-pratinjau) kemudian gelembung dari target hingga akar.
Pemisahan antara terowongan dan fase gelembung ini membuat implementasi fitur seperti akselerator keyboard bekerja secara konsisten dalam dunia komposit. Di User32 Anda akan menerapkan akselerator keyboard dengan memiliki satu tabel global yang berisi semua akselerator yang ingin Anda dukung (pemetaan Ctrl+N ke "Baru"). Di dispatcher untuk aplikasi Anda, Anda akan memanggil TranslateAccelerator yang akan mengintai pesan input di User32 dan menentukan apakah ada yang cocok dengan akselerator terdaftar. Dalam WPF, ini tidak akan berfungsi karena sistem sepenuhnya "dapat disusam" - elemen apa pun dapat menangani dan menggunakan akselerator keyboard apa pun. Memiliki model dua fase ini untuk input memungkinkan komponen untuk mengimplementasikan "TranslateAccelerator" mereka sendiri.
Untuk melangkah lebih jauh, UIElement perkenalkan juga gagasan CommandBindings. Sistem perintah WPF memungkinkan pengembang untuk menentukan fungsionalitas dalam hal titik akhir perintah - sesuatu yang mengimplementasikan ICommand. Pengikatan perintah memungkinkan elemen untuk menentukan pemetaan antara gerakan input (Ctrl+N) dan perintah (Baru). Gerakan input dan definisi perintah dapat diperluas, dan dapat dikabel bersama pada waktu penggunaan. Ini membuatnya sepele, misalnya, untuk memungkinkan pengguna akhir menyesuaikan pengikatan kunci yang ingin mereka gunakan dalam aplikasi.
Untuk titik ini dalam topik ini, fitur "inti" WPF – fitur yang diimplementasikan dalam perakitan PresentationCore, telah menjadi fokusnya. Saat membangun WPF, pemisahan bersih antara potongan dasar (seperti kontrak untuk tata letak dengan Ukuran dan Susun) dan potongan kerangka kerja (seperti implementasi tata letak tertentu seperti Grid) adalah hasil yang diinginkan. Tujuannya adalah untuk memberikan titik ekstensibilitas rendah dalam tumpukan yang akan memungkinkan pengembang eksternal untuk membuat kerangka kerja mereka sendiri jika diperlukan.
System.Windows.FrameworkElement
FrameworkElement dapat dilihat dengan dua cara yang berbeda. Ini memperkenalkan serangkaian kebijakan dan kustomisasi pada subsistem yang diperkenalkan di lapisan WPF yang lebih rendah. Ini juga memperkenalkan satu set subsistem baru.
Kebijakan utama yang diperkenalkan adalah sekeliling FrameworkElement tata letak aplikasi. FrameworkElement dibangun pada kontrak tata letak dasar yang diperkenalkan oleh UIElement dan menambahkan gagasan "slot" tata letak yang memudahkan penulis tata letak untuk memiliki semantik tata letak yang digerakkan properti yang konsisten. Properti seperti HorizontalAlignment, VerticalAlignment, MinWidth, dan Margin (untuk beberapa nama) memberikan semua komponen yang berasal dari FrameworkElement perilaku yang konsisten di dalam kontainer tata letak.
FrameworkElement juga memberikan paparan API yang lebih mudah ke banyak fitur yang ditemukan di lapisan inti WPF. Misalnya, FrameworkElement menyediakan akses langsung ke animasi melalui BeginStoryboard metode . menyediakan Storyboard cara untuk membuat skrip beberapa animasi terhadap sekumpulan properti.
Dua hal paling penting yang FrameworkElement diperkenalkan adalah pengikatan dan gaya data.
Subsistem pengikatan data di WPF harus relatif akrab bagi siapa saja yang telah menggunakan Formulir Windows atau ASP.NET untuk membuat antarmuka pengguna aplikasi (UI). Dalam setiap sistem ini, ada cara sederhana untuk mengekspresikan bahwa Anda ingin satu atau beberapa properti dari elemen tertentu terikat ke sepotong data. WPF memiliki dukungan penuh untuk pengikatan properti, transformasi, dan pengikatan daftar.
Salah satu fitur paling menarik dari pengikatan data di WPF adalah pengenalan templat data. Templat data memungkinkan Anda menentukan secara deklaratif bagaimana sepotong data harus divisualisasikan. Alih-alih membuat antarmuka pengguna kustom yang dapat terikat ke data, Anda dapat membalikkan masalah dan membiarkan data menentukan tampilan yang akan dibuat.
Gaya benar-benar bentuk pengikatan data yang ringan. Menggunakan gaya, Anda dapat mengikat sekumpulan properti dari definisi bersama ke satu atau beberapa instans elemen. Gaya diterapkan ke elemen baik dengan referensi eksplisit (dengan mengatur Style properti) atau secara implisit dengan mengaitkan gaya dengan jenis CLR elemen.
System.Windows.Controls.Controls
Fitur paling signifikan kontrol adalah templat. Jika Anda berpikir tentang sistem komposisi WPF sebagai sistem penyajian mode yang dipertahankan, pembuatan templat memungkinkan kontrol untuk menggambarkan penyajiannya dengan cara yang berparameter dan deklaratif. A ControlTemplate benar-benar tidak lebih dari skrip untuk membuat sekumpulan elemen anak, dengan pengikatan ke properti yang ditawarkan oleh kontrol.
Control menyediakan sekumpulan properti stok, Foreground, Background, Padding, untuk beberapa nama, penulis templat mana yang kemudian dapat digunakan untuk menyesuaikan tampilan kontrol. Implementasi kontrol menyediakan model data dan model interaksi. Model interaksi mendefinisikan sekumpulan perintah (seperti Tutup untuk jendela) dan pengikatan ke gerakan input (seperti mengklik X merah di sudut atas jendela). Model data menyediakan sekumpulan properti untuk menyesuaikan model interaksi atau menyesuaikan tampilan (ditentukan oleh templat).
Pemisahan antara model data (properti), model interaksi (perintah dan peristiwa), dan model tampilan (templat) memungkinkan penyesuaian lengkap tampilan dan perilaku kontrol.
Aspek umum dari model data kontrol adalah con mode tenda l. Jika Anda melihat kontrol seperti Button, Anda akan melihat bahwa ia memiliki properti bernama "Konten" jenis Object. Dalam Formulir Windows dan ASP.NET, properti ini biasanya akan menjadi string - namun yang membatasi jenis konten yang dapat Anda masukkan ke dalam tombol. Konten untuk tombol dapat berupa string sederhana, objek data kompleks, atau seluruh pohon elemen. Dalam kasus objek data, templat data digunakan untuk membuat tampilan.
Ringkasan
WPF dirancang untuk memungkinkan Anda membuat sistem presentasi dinamis dan berbasis data. Setiap bagian dari sistem dirancang untuk membuat objek melalui set properti yang mendorong perilaku. Pengikatan data adalah bagian mendasar dari sistem, dan terintegrasi di setiap lapisan.
Aplikasi tradisional membuat tampilan lalu mengikat beberapa data. Di WPF, segala sesuatu tentang kontrol, setiap aspek tampilan, dihasilkan oleh beberapa jenis pengikatan data. Teks yang ditemukan di dalam tombol ditampilkan dengan membuat kontrol yang terdiri di dalam tombol dan mengikat tampilannya ke properti konten tombol.
Ketika Anda mulai mengembangkan aplikasi berbasis WPF, itu akan terasa sangat akrab. Anda dapat mengatur properti, menggunakan objek, dan pengikatan data dengan cara yang sama seperti yang dapat Anda gunakan Formulir Windows atau ASP.NET. Dengan penyelidikan yang lebih dalam tentang arsitektur WPF, Anda akan menemukan bahwa kemungkinan ada untuk membuat aplikasi yang jauh lebih kaya yang pada dasarnya memperlakukan data sebagai penggerak inti aplikasi.
Baca juga
.NET Desktop feedback