Intro
Dalam MVVM, praktik yang biasa dilakukan adalah meminta Views menemukan ViewModels mereka dengan menyelesaikannya dari penampung injeksi ketergantungan (DI). Ini terjadi secara otomatis ketika container diminta untuk menyediakan (menyelesaikan) sebuah instance dari kelas View. Penampung memasukkan ViewModel ke dalam Tampilan dengan memanggil konstruktor Tampilan yang menerima parameter ViewModel; skema ini disebut inversion of control (IoC).
Manfaat DI
Manfaat utama di sini adalah bahwa penampung dapat dikonfigurasi pada waktu proses dengan petunjuk tentang cara menyelesaikan jenis yang kami minta darinya. Hal ini memungkinkan testabilitas yang lebih besar dengan menginstruksikannya untuk menyelesaikan jenis (Views dan ViewModels) yang kita gunakan saat aplikasi kita benar-benar berjalan, tetapi menginstruksikannya secara berbeda saat menjalankan pengujian unit untuk aplikasi tersebut. Dalam kasus terakhir, aplikasi bahkan tidak akan memiliki UI (tidak berjalan; hanya pengujiannya) sehingga penampung akan menyelesaikan tiruan sebagai ganti jenis "normal" yang digunakan saat aplikasi berjalan.
Masalah yang berasal dari DI
Sejauh ini kita telah melihat bahwa pendekatan DI memungkinkan kemudahan pengujian untuk aplikasi dengan menambahkan lapisan abstraksi selama pembuatan komponen aplikasi. Ada satu masalah dengan pendekatan ini: pendekatan ini tidak cocok dengan desainer visual seperti Microsoft Expression Blend.
Masalahnya adalah bahwa dalam proses aplikasi normal dan pengujian unit, seseorang harus menyiapkan container dengan instruksi tentang tipe apa yang harus diselesaikan; Selain itu, seseorang harus meminta penampung untuk menyelesaikan Tampilan sehingga ViewModels dapat dimasukkan ke dalamnya.
Namun, dalam waktu desain tidak ada kode kami yang berjalan . Perancang mencoba menggunakan refleksi untuk membuat contoh Tampilan kami, yang berarti:
- Jika konstruktor Tampilan memerlukan contoh ViewModel, perancang tidak akan dapat membuat contoh Tampilan sama sekali - ini akan menghasilkan kesalahan dengan cara yang terkontrol
- Jika View memiliki konstruktor tanpa parameter, View akan dipakai, tetapi
DataContext
akan null
begitu kita mendapatkan tampilan "kosong" di desainer - yang tidak terlalu berguna
Masuk ke ViewModelLocator
ViewModelLocator adalah abstraksi tambahan yang digunakan seperti ini:
- Tampilan itu sendiri membuat instance ViewModelLocator sebagai bagian dari sumber dayanya dan menghubungkan DataContext-nya ke properti ViewModel pelacak
- Locator entah bagaimana mendeteksi jika kita dalam mode desain
- Jika tidak dalam mode desain, locator mengembalikan ViewModel yang diselesaikannya dari kontainer DI, seperti dijelaskan di atas
- Jika dalam mode desain, pencari lokasi mengembalikan ViewModel "tiruan" yang tetap menggunakan logikanya sendiri (ingat: tidak ada kontainer dalam waktu desain!); ViewModel ini biasanya sudah terisi sebelumnya dengan data dummy
Tentu saja ini berarti bahwa View harus memiliki konstruktor tanpa parameter untuk memulai (jika tidak, desainer tidak akan dapat membuatnya).
Ringkasan
ViewModelLocator adalah idiom yang memungkinkan Anda menyimpan manfaat DI dalam aplikasi MVVM Anda sekaligus memungkinkan kode Anda berfungsi baik dengan desainer visual. Ini terkadang disebut "daya campuran" dari aplikasi Anda (mengacu pada Campuran Ekspresi).
Setelah mencerna hal di atas, lihat contoh praktis di sini .
Terakhir, menggunakan template data bukanlah alternatif untuk menggunakan ViewModelLocator, tetapi alternatif untuk menggunakan pasangan View / ViewModel eksplisit untuk bagian UI Anda. Seringkali Anda mungkin menemukan bahwa tidak perlu menentukan Tampilan untuk ViewModel karena Anda bisa menggunakan templat data sebagai gantinya.
d:DataContext="{d:DesignInstance MockViewModels:MockMainWindowModel, IsDesignTimeCreatable=True}"
. Tujuan dari Locator adalah untuk benar-benar mengaktifkan DI pada Views, karena WPF sangat buruk dalam menyediakannya. Contoh: Anda memiliki Jendela Utama yang membuka beberapa Jendela Dialog. Untuk menyelesaikan DI di Jendela Dialog dengan cara biasa, Anda harus meneruskannya sebagai dependensi di Jendela Utama! Ini dihindari dengan View Locator.Contoh implementasi jawaban @ Jon
Saya memiliki kelas pencari model tampilan. Setiap properti akan menjadi turunan dari model tampilan yang akan saya alokasikan pada tampilan saya. Saya dapat memeriksa apakah kode tersebut berjalan dalam mode desain atau tidak menggunakan
DesignerProperties.GetIsInDesignMode
. Ini memungkinkan saya untuk menggunakan model tiruan selama waktu desain dan objek nyata saat saya menjalankan aplikasi.Dan untuk menggunakannya, saya dapat menambahkan pencari lokasi saya ke
App.xaml
sumber daya:Dan kemudian untuk memasang tampilan Anda (mis: MainView.xaml) ke viewmodel Anda:
sumber
this
selaindummy
?Saya tidak mengerti mengapa jawaban lain dari pertanyaan ini melingkupi Desainer.
Tujuan dari View Model Locator adalah untuk memungkinkan View Anda membuat contoh ini (ya, View Model Locator = View First):
bukan hanya ini:
dengan menyatakan ini:
Di mana
ViewModelLocator
kelas, yang mereferensikan IoC dan begitulah cara memecahkanMainWindowModel
properti yang dieksposnya.Ini tidak ada hubungannya dengan menyediakan model tampilan Mock ke tampilan Anda. Jika Anda menginginkan itu, lakukan saja
View Model Locator adalah pembungkus di sekitar beberapa (ada) wadah Pembalikan Kontrol, seperti Unity misalnya.
Mengacu pada:
sumber