Mulai cepat dengan WPF. Bagian 1. Binding, INotifyPropertyChanged, dan MVVM

Halo semuanya!


Karena berbagai alasan, kebanyakan dari kita menggunakan aplikasi desktop, setidaknya browser :) Dan beberapa dari kita perlu menulis sendiri. Pada artikel ini, saya ingin membahas proses pengembangan aplikasi desktop sederhana menggunakan teknologi Windows Presentation Foundation (WPF) dan menerapkan pola MVVM. Mereka yang ingin terus membaca, tolong, di bawah kucing.


Saya pikir tidak perlu mengatakan bahwa WPF adalah pengembangan Microsoft :) Teknologi ini dirancang untuk mengembangkan aplikasi desktop untuk Windows, dimulai dengan Windows XP. Kenapa begitu? Ini disebabkan oleh kenyataan bahwa WPF berjalan di atas platform .NET, persyaratan minimumnya adalah Windows XP dan yang lebih baru. Sayangnya, WPF tidak berfungsi pada platform lain, meskipun ada kemungkinan bahwa ini akan berubah dalam waktu dekat: kerangka kerja Avalonia berbasis WPF sedang dalam pengembangan .


Apa yang spesial dari WPF?


Dua perbedaan utama antara WPF dan alat bangunan desktop lainnya:


  • Bahasa marka XAML untuk menandai antarmuka jendela itu sendiri.
  • Rendering melalui DirectX, akselerasi grafis perangkat keras.

Saya tidak akan merinci, karena ini bukan topik artikelnya. Jika tertarik, maka google XAML, rendering WPF, milcore.dll dan DirectX :)


Tentang apa artikel ini?


Artikel ini berisi contoh aplikasi yang dibangun di atas teknologi WPF:



Saya akan mencoba mengarahkan materi artikel ke arah yang praktis dengan gaya β€œulangi setelah saya” dengan penjelasan.


Apa yang kita butuhkan untuk mengulang artikel itu?


Sedikit pengalaman pengembangan dalam C # :) Minimal, Anda perlu memahami sintaks bahasa dengan baik. Anda juga akan memerlukan mesin Windows (Menangkan 10 dalam contoh) dengan Visual Studio diinstal di dalamnya (dalam contoh itu akan 2017, ada versi Komunitas gratis). Saat memasang VS, Anda harus mengaktifkan dukungan untuk pengembangan desktop untuk platform .NET


gambar


Juga di bagian ini saya akan menjelaskan pembuatan suatu proyek.


Kami meluncurkan VS, membuat proyek baru, pilih jenis aplikasi Aplikasi WPF (.NET Framework) (Anda dapat memasukkannya di bilah pencarian di kanan atas), sebut saja apa pun yang Anda suka.


gambar


Setelah membuat proyek baru, jendela editor antarmuka terbuka, sepertinya ini bagi saya


gambar


Di bagian bawah terdapat editor tata letak, di bagian atas terdapat pratinjau antarmuka jendela, tetapi Anda dapat mengubah lokasi relatif editor kode dan pratinjau antarmuka sehingga mereka akan ditempatkan dalam urutan horizontal menggunakan tombol-tombol ini (di sebelah kanan perbatasan kedua area):


gambar


Sebelum Anda mulai


Elemen jendela (mereka juga disebut kontrol dari kata Control ) harus ditempatkan di dalam wadah atau di dalam elemen lain dari tipe ContentControl. Wadah adalah kontrol khusus yang memungkinkan Anda menempatkan beberapa kontrol anak di dalam dan mengatur pengaturan bersama mereka. Contoh wadah:


  • Kisi - memungkinkan Anda untuk mengatur elemen berdasarkan kolom dan baris, lebar setiap kolom atau baris dikonfigurasikan secara terpisah.
  • StackPanel - memungkinkan Anda mengatur anak-anak dalam satu baris atau kolom.

Ada wadah lain. Karena wadah juga merupakan kontrol, di dalam wadah mungkin ada wadah bersarang yang berisi wadah bersarang dan sebagainya. Ini memungkinkan Anda mengatur kontrol secara fleksibel satu sama lain. Juga, dengan bantuan kontainer, kita dapat dengan fleksibel mengontrol perilaku kontrol bersarang ketika mengubah ukuran jendela.


Antarmuka MVVM dan INotifyPropertyChanged. Salinan teks.


Hasil dari contoh ini akan menjadi aplikasi dengan dua kontrol, di mana Anda dapat mengedit teks, dan yang lain hanya melihat. Perubahan dari satu ke yang lain akan ditransfer secara sinkron tanpa menyalin teks secara eksplisit menggunakan binding .


Jadi, kami memiliki proyek yang baru dibuat (saya menamakannya Ex1 ), buka editor tata letak dan pertama-tama ganti wadah default ( <Grid> </Grid> ) dengan <StackPanel> </StackPanel> . Wadah ini akan cukup, karena kita hanya perlu menempatkan dua kontrol satu di atas yang lain. Kami secara eksplisit menentukan bagaimana komponen akan diatur dengan menambahkan properti Orientation = "Vertical" . Tambahkan beberapa elemen di dalam tumpukan panel: bidang untuk memasukkan teks dan bidang untuk menampilkan teks. Karena kontrol ini tidak akan berisi kode tertanam, Anda dapat mendeskripsikannya dengan tag penutup sendiri (lihat kode di bawah). Setelah semua prosedur di atas, kode deskripsi kontainer dan kontrol bersarang harus mengambil bentuk berikut:


<StackPanel Orientation="Vertical"> <TextBox /> <TextBlock /> </StackPanel> 

Sekarang mari kita fokus pada tujuan dari contoh ini. Kami ingin bahwa ketika mengetik di kotak teks, teks yang sama ditampilkan secara sinkron di blok teks, sambil menghindari operasi penyalinan eksplisit. Kita membutuhkan semacam entitas penghubung, dan di sini kita sampai pada hal yang mengikat , yang disebutkan di atas. Mengikat dalam terminologi WPF adalah mekanisme yang memungkinkan Anda untuk mengaitkan beberapa properti kontrol dengan beberapa properti objek kelas C # dan secara bersama memperbarui properti ini ketika salah satu bagian dari bundel berubah (ini dapat bekerja di satu, yang lain, atau kedua arah sekaligus). Bagi mereka yang terbiasa dengan Qt, Anda dapat menggambar analogi slot dan sinyal. Agar tidak memperpanjang waktu, mari beralih ke kode.


Jadi, untuk mengatur pengikatan, Anda memerlukan properti dari kontrol dan beberapa properti dari kelas C # tertentu. Pertama, mari kita cari tahu kode XAML. Teks dari kedua kontrol disimpan di properti Teks, jadi tambahkan ikatan untuk properti ini. Ini dilakukan seperti ini:


 <TextBox Text="{Binding}"/> <TextBlock Text="{Binding}"/> 

Kami membuat pengikatan, tetapi untuk saat ini tidak jelas mengapa :) Kami membutuhkan objek dari beberapa kelas dan beberapa properti di objek ini yang akan dibuat pengikatannya (seperti yang mereka katakan, yang perlu Anda ikat).


Jadi apa kelas ini? Kelas ini disebut model tampilan dan berfungsi sebagai tautan antara tampilan (antarmuka atau bagian-bagiannya) dan model (model, mis. Bagian-bagian dari kode yang bertanggung jawab untuk logika aplikasi. Ini memungkinkan Anda untuk memisahkan (sampai batas tertentu ) logika aplikasi dari antarmuka (tampilan, tampilan) disebut pola Model-View-ViewModel (MVVM) .Dalam WPF, kelas ini juga disebut DataContext .


Namun, hanya menulis model tampilan kelas tidak cukup. Penting untuk menginformasikan mekanisme pengikatan bahwa properti model tampilan atau properti tampilan telah berubah. Untuk melakukan ini, ada antarmuka khusus INotifyPropertyChanged , yang berisi acara PropertyChanged . Kami mengimplementasikan antarmuka ini dalam rangka BaseViewModel kelas dasar. Di masa depan, kami akan mewarisi semua model tampilan kami dari kelas dasar ini agar tidak menduplikasi implementasi antarmuka. Jadi, tambahkan direktori ViewModels ke proyek, dan tambahkan file BaseViewModel.cs ke direktori ini. Kami mendapatkan struktur proyek berikut:


gambar


Kode implementasi untuk model tampilan dasar:


 using System.ComponentModel; namespace Ex1.ViewModels { public class BaseViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName = "") { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } } 

Mari kita buat model tampilan kita untuk kelas MainWindow kita, yang diturunkan dari basis satu. Untuk melakukan ini, di direktori ViewModels yang sama, buat file MainWindowViewModel.cs , di dalamnya akan ada kode seperti itu:


 namespace Ex1.ViewModels { public class MainWindowViewModel : BaseViewModel { } } 

Hebat! Sekarang kita perlu menambahkan properti ke model tampilan ini, ke mana kita akan mengikat teks kontrol kita. Karena ini adalah teks, jenis properti ini harus berupa string :


 public string SynchronizedText { get; set; } 

Hasilnya, kami mendapatkan kode seperti itu


 namespace Ex1.ViewModels { public class MainWindowViewModel : BaseViewModel { public string SynchronizedText { get; set; } } } 

Jadi, tampaknya, mereka berhasil. Tetap mengikat properti ini dari tampilan dan siap. Mari kita lakukan sekarang:


 <TextBox Text="{Binding Path=SynchronizedText}"/> <TextBlock Text="{Binding Path=SynchronizedText}"/> 

Nishtyak, kami memulai proyek, kami mengetikkan kotak teks iiiii ... tidak ada yang terjadi))) Yah, tidak apa-apa, sebenarnya kami berjalan dengan cara yang benar, kami hanya belum mencapai titik yang benar.


Saya mengusulkan untuk berhenti sejenak dan berpikir tentang apa yang kita lewatkan. Kami punya pandangan. Viewmodel juga. Properti seperti zabindili. Antarmuka yang diinginkan diimplementasikan. Kami melakukan banyak pekerjaan untuk menyalin garis teks yang menyedihkan, mengapa kami membutuhkan ini ???!?! 111


Oke, bercanda samping. Kami lupa membuat objek model tampilan dan sesuatu yang lain (lebih lanjut tentang itu nanti). Kami menggambarkan kelas itu sendiri, tetapi ini tidak berarti apa-apa, karena kami tidak memiliki objek dari kelas ini. Oke, di mana Anda perlu menyimpan tautan ke objek ini? Lebih dekat ke awal contoh, saya menyebutkan DataContext tertentu yang digunakan dalam WPF. Jadi, tampilan apa pun memiliki properti DataContext tempat kami dapat menetapkan tautan ke model tampilan kami. Ayo lakukan. Untuk melakukan ini, buka file MainWindow.xaml dan tekan F7 untuk membuka kode untuk tampilan ini. Hampir kosong, hanya memiliki konstruktor kelas jendela. Tambahkan kreasi model tampilan kami ke dalamnya dan letakkan di DataContext jendela (jangan lupa untuk menambahkan menggunakan dengan namespace yang diinginkan):


 public MainWindow() { InitializeComponent(); this.DataContext = new MainWindowViewModel(); } 

Itu sederhana, tetapi masih belum cukup. Namun, ketika aplikasi dimulai, tidak ada sinkronisasi teks yang terjadi. Apa lagi yang perlu dilakukan?


Anda perlu meningkatkan acara PropertyChanged ketika properti SynchronizedText berubah dan menginformasikan pandangan bahwa ia harus memantau acara ini. Jadi, untuk memicu acara, ubah kode model tampilan:


 public class MainWindowViewModel : BaseViewModel { private string _synchronizedText; public string SynchronizedText { get => _synchronizedText; set { _synchronizedText = value; OnPropertyChanged(nameof(SynchronizedText)); } } } 

Apa yang sudah kita lakukan di sini? Kami menambahkan bidang tersembunyi untuk menyimpan teks, membungkusnya di properti yang sudah ada, dan ketika mengubah properti ini kami tidak hanya mengubah bidang tersembunyi, tetapi juga memanggil metode OnPropertyChanged yang didefinisikan dalam model tampilan dasar dan meningkatkan acara PropertyChanged yang dideklarasikan dalam antarmuka INotifyPropertyChanged , juga diterapkan di basis lihat model. Ternyata setiap kali teks diubah, acara PropertyChanged terjadi, di mana nama properti model tampilan yang diubah dilewatkan.


Yah, hampir semuanya, garis finish! Tetap menentukan pandangan bahwa ia harus mendengarkan acara PropertyChanged :


 <TextBox Text="{Binding Path=SynchronizedText, UpdateSourceTrigger=PropertyChanged, Mode=OneWayToSource}"/> <TextBlock Text="{Binding Path=SynchronizedText, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"/> 

Selain fakta bahwa kami mengindikasikan pemicu pembaruan yang harus dilakukan, kami juga menunjukkan ke arah mana pembaruan ini dilacak: dari tampilan ke tampilan model atau sebaliknya. Karena kami memasukkan teks di kotak teks, kami hanya tertarik pada perubahan dalam tampilan, jadi kami memilih mode OneWayToSource . Dalam hal blok teks, semuanya justru sebaliknya: kami tertarik pada perubahan dalam model tampilan untuk menampilkannya dalam tampilan, jadi kami memilih mode OneWay . Jika kami ingin perubahan dilacak di kedua arah, kami tidak dapat menentukan Mode sama sekali, atau menentukan TwoWay secara eksplisit.


Jadi, jalankan programnya, ketikkan teksnya dan voi-la! Teksnya berubah secara sinkron, dan kami tidak menyalin apa pun di mana pun!


gambar


Terima kasih atas perhatiannya, untuk dilanjutkan. Kami akan menangani DataTemplate dan pola Command.

Source: https://habr.com/ru/post/id427325/


All Articles