Dalam pola MVVM untuk WPF, penanganan dialog adalah salah satu operasi yang lebih kompleks. Karena model tampilan Anda tidak tahu apa-apa tentang tampilan, komunikasi dialog bisa menarik. Saya dapat mengekspos sebuahICommand
bahwa ketika tampilan memanggilnya, sebuah dialog dapat muncul.
Adakah yang tahu cara yang baik untuk menangani hasil dari dialog? Saya berbicara tentang dialog windows seperti MessageBox
.
Salah satu cara kami melakukan ini adalah memiliki acara di viewmodel yang berlangganan akan berlangganan ketika dialog diperlukan.
public event EventHandler<MyDeleteArgs> RequiresDeleteDialog;
Ini tidak apa-apa, tetapi itu berarti bahwa tampilan memerlukan kode yang merupakan sesuatu yang ingin saya hindari.
Jawaban:
Saya menyarankan untuk tidak melanjutkan dialog modal tahun 1990 dan alih-alih menerapkan kontrol sebagai overlay (kanvas + penentuan posisi absolut) dengan visibilitas yang terikat pada boolean di VM. Lebih dekat ke kontrol tipe ajax.
Ini sangat berguna:
seperti dalam:
Inilah cara saya menerapkannya sebagai kontrol pengguna. Mengklik 'x' menutup kontrol dalam baris kode di kode kontrol pengguna di belakang. (Karena saya memiliki Tampilan saya di .exe dan ViewModels di dll, saya tidak merasa buruk tentang kode yang memanipulasi UI.)
sumber
Anda harus menggunakan mediator untuk ini. Mediator adalah pola desain umum yang juga dikenal sebagai Messenger dalam beberapa implementasinya. Ini adalah paradigma tipe Register / Beritahu dan memungkinkan ViewModel dan Tampilan Anda untuk berkomunikasi melalui mekanisme pesan yang digabungkan dengan rendah.
Anda harus memeriksa grup Google WPF Disciples, dan cukup mencari Mediator. Anda akan jauh lebih senang dengan jawabannya ...
Namun Anda dapat mulai dengan ini:
http://joshsmithonwpf.wordpress.com/2009/04/06/a-mediator-prototype-for-wpf-apps/
Nikmati !
Sunting: Anda dapat melihat jawaban untuk masalah ini dengan MVVM Light Toolkit di sini:
http://mvvmlight.codeplex.com/Thread/View.aspx?ThreadId=209338
sumber
Dialog MVVM yang baik harus:
Sayangnya, WPF tidak menyediakan fitur-fitur ini. Menampilkan dialog memerlukan panggilan kode-balik
ShowDialog()
. Kelas Window, yang mendukung dialog, tidak dapat dideklarasikan dalam XAML sehingga tidak dapat dengan mudah didekatiDataContext
.Untuk mengatasi ini, saya menulis kontrol rintisan XAML yang duduk di pohon logis dan relay penyatuan data ke
Window
dan menangani menampilkan dan menyembunyikan dialog. Anda dapat menemukannya di sini: http://www.codeproject.com/KB/WPF/XAMLDialog.aspxIni sangat sederhana untuk digunakan dan tidak memerlukan perubahan aneh pada ViewModel Anda dan tidak memerlukan acara atau pesan. Panggilan dasar terlihat seperti ini:
Anda mungkin ingin menambahkan gaya yang ditetapkan
Showing
. Saya jelaskan di artikel saya. Saya harap ini membantu Anda.sumber
"Showing a dialog requires a code-behind"
mmm Anda bisa menyebutnya di ViewModelSaya menggunakan ini pendekatan untuk dialog dengan MVVM.
Yang harus saya lakukan sekarang adalah memanggil yang berikut dari model tampilan saya.
sumber
Solusi saya saat ini menyelesaikan sebagian besar masalah yang Anda sebutkan namun sepenuhnya abstrak dari platform hal-hal spesifik dan dapat digunakan kembali. Saya juga tidak menggunakan kode-belakang hanya mengikat dengan DelegateCommands yang mengimplementasikan ICommand. Dialog pada dasarnya adalah View - kontrol terpisah yang memiliki ViewModel sendiri dan ditampilkan dari ViewModel pada layar utama tetapi dipicu dari UI melalui pengikatan DelagateCommand.
Lihat solusi Silverlight 4 lengkap di sini. Dialog Modal dengan MVVM dan Silverlight 4
sumber
Saya benar-benar berjuang dengan konsep ini untuk sementara waktu ketika belajar (masih belajar) MVVM. Apa yang saya putuskan, dan apa yang saya pikirkan sudah diputuskan orang lain tetapi yang tidak jelas bagi saya adalah ini:
Pikiran asli saya adalah bahwa ViewModel tidak boleh diizinkan untuk memanggil kotak dialog secara langsung karena tidak ada bisnis yang memutuskan bagaimana dialog akan muncul. Karena ini saya mulai berpikir tentang bagaimana saya bisa mengirimkan pesan seperti yang saya miliki di MVP (yaitu View.ShowSaveFileDialog ()). Namun, saya pikir ini adalah pendekatan yang salah.
Tidak masalah bagi ViewModel untuk memanggil dialog secara langsung. Namun, ketika Anda menguji ViewModel, itu berarti dialog akan muncul selama pengujian Anda, atau gagal semuanya (tidak pernah benar-benar mencoba ini).
Jadi, yang perlu terjadi adalah saat pengujian adalah menggunakan versi "uji" dialog Anda. Ini berarti bahwa untuk selamanya dialog yang Anda miliki, Anda perlu membuat Interface dan mengejek respons dialog atau membuat tiruan pengujian yang akan memiliki perilaku default.
Anda seharusnya sudah menggunakan semacam Service Locator atau IoC yang dapat Anda konfigurasi untuk memberikan versi yang benar tergantung pada konteksnya.
Menggunakan pendekatan ini, ViewModel Anda masih dapat diuji dan tergantung pada bagaimana Anda mengejek dialog Anda, Anda dapat mengontrol perilaku.
Semoga ini membantu.
sumber
Ada dua cara yang baik untuk melakukan ini, 1) layanan dialog (mudah, bersih), dan 2) lihat dibantu. View dibantu menyediakan beberapa fitur yang rapi, tetapi biasanya tidak sepadan.
LAYANAN DIALOG
a) antarmuka layanan dialog seperti via konstruktor atau wadah ketergantungan:
interface IDialogService { Task ShowDialogAsync(DialogViewModel dlgVm); }
b) Implementasi IDialogService Anda harus membuka jendela (atau menyuntikkan kontrol ke jendela aktif), membuat tampilan yang sesuai dengan nama tipe dlgVm yang diberikan (menggunakan registrasi atau konvensi wadah atau ContentPresenter dengan tipe DataTemplates terkait). ShowDialogAsync harus membuat TaskCompletionSource dan mengembalikan proposinya .Task. Kelas DialogViewModel sendiri membutuhkan acara yang dapat Anda panggil di kelas turunan saat Anda ingin menutup, dan tonton di tampilan dialog untuk benar-benar menutup / menyembunyikan dialog dan menyelesaikan TaskCompletionSource.
b) Untuk menggunakannya, cukup panggil tunggu ini. DialogService.ShowDialog (myDlgVm) pada contoh Anda dari beberapa kelas yang diturunkan dari DialogViewModel. Setelah menunggu pengembalian, lihat properti yang telah Anda tambahkan pada dialog VM Anda untuk menentukan apa yang terjadi; Anda bahkan tidak memerlukan panggilan balik.
LIHAT BANTUAN
Ini membuat Anda mendengarkan acara di model tampilan. Ini semua bisa dibungkus menjadi Perilaku Blend untuk menghindari kode di belakang dan penggunaan sumber daya jika Anda cenderung (FMI, subkelas kelas "Perilaku" untuk melihat semacam properti terlampir Blendable pada steroid). Untuk saat ini, kami akan melakukan ini secara manual pada setiap tampilan:
a) Buat OpenXXXXXDialogEvent dengan payload kustom (kelas turunan DialogViewModel).
b) Minta tampilan untuk berlangganan acara tersebut di acara OnDataContextChanged-nya. Pastikan untuk menyembunyikan dan berhenti berlangganan jika nilai lama! = Null dan pada acara Window's Unloaded.
c) Ketika acara menyala, mintalah tampilan untuk membuka tampilan Anda, yang mungkin ada di sumber daya pada halaman Anda, atau Anda dapat menemukannya dengan konvensi di tempat lain (seperti dalam pendekatan layanan dialog).
Pendekatan ini lebih fleksibel, tetapi membutuhkan lebih banyak pekerjaan untuk digunakan. Saya tidak banyak menggunakannya. Satu keuntungan yang bagus adalah kemampuan untuk menempatkan tampilan secara fisik di dalam tab, misalnya. Saya telah menggunakan algoritma untuk menempatkannya di batas kontrol pengguna saat ini, atau jika tidak cukup besar, melintasi pohon visual sampai wadah yang cukup besar ditemukan.
Ini memungkinkan dialog menjadi dekat dengan tempat mereka sebenarnya digunakan, hanya meredupkan bagian dari aplikasi yang terkait dengan aktivitas saat ini, dan membiarkan pengguna bergerak di dalam aplikasi tanpa harus secara manual mendorong dialog, bahkan memiliki beberapa kuasi- dialog modal terbuka pada tab atau sub-tampilan yang berbeda.
sumber
Gunakan perintah yang dapat dibekukan
sumber
Saya pikir penanganan dialog harus menjadi tanggung jawab pandangan, dan pandangan perlu memiliki kode untuk mendukungnya.
Jika Anda mengubah ViewModel - Lihat interaksi untuk menangani dialog maka ViewModel bergantung pada implementasi itu. Cara paling sederhana untuk mengatasi masalah ini adalah membuat View bertanggung jawab untuk melakukan tugas. Jika itu berarti menampilkan dialog maka baik-baik saja, tetapi juga bisa menjadi pesan status di bilah status dll.
Maksud saya adalah bahwa seluruh titik pola MVVM adalah memisahkan logika bisnis dari GUI, jadi Anda tidak boleh mencampurkan logika GUI (untuk menampilkan dialog) di lapisan bisnis (ViewModel).
sumber
Alternatif yang menarik adalah dengan menggunakan Pengontrol yang bertanggung jawab untuk menampilkan tampilan (dialog).
Cara kerjanya ditunjukkan oleh WPF Application Framework (WAF) .
sumber
Mengapa tidak hanya membuat acara di VM dan berlangganan acara di tampilan? Ini akan membuat logika aplikasi dan tampilan terpisah dan masih memungkinkan Anda untuk menggunakan jendela anak untuk dialog.
sumber
Saya telah menerapkan Perilaku yang mendengarkan Pesan dari ViewModel. Ini didasarkan pada solusi Laurent Bugnion, tetapi karena tidak menggunakan kode di belakang dan lebih dapat digunakan kembali, saya pikir itu lebih elegan.
Cara membuat WPF berperilaku seolah-olah MVVM didukung di luar kotak
sumber
Saya pikir view bisa memiliki kode untuk menangani event dari model view.
Bergantung pada peristiwa / skenario, itu juga bisa memiliki pemicu acara yang berlangganan untuk melihat model acara, dan satu atau lebih tindakan untuk meminta tanggapan.
sumber
Saya memiliki situasi yang sama dan membungkus MessageBox menjadi kontrol tak terlihat desainer. Detailnya ada di blog saya
http://geekswithblogs.net/mukapu/archive/2010/03/12/user-prompts-messagebox-with-mvvm.aspx
Hal yang sama dapat diperluas ke setiap dialog modal, kontrol penelusuran file, dll.
sumber
Saya menggulung jendela pemuat saya sendiri yang dijelaskan dalam jawaban untuk pertanyaan ini:
Mengelola banyak tampilan WPF dalam suatu aplikasi
sumber
Karl Shifflett telah membuat contoh aplikasi untuk menampilkan kotak dialog menggunakan pendekatan layanan dan pendekatan Prism InteractionRequest.
Saya suka pendekatan layanan - Ini kurang fleksibel sehingga pengguna cenderung untuk memecahkan sesuatu :) Ini juga konsisten dengan bagian WinForms dari aplikasi saya (MessageBox.Show) Tetapi jika Anda berencana untuk menampilkan banyak dialog yang berbeda, maka InteractionRequest adalah cara yang lebih baik untuk pergi.
http://karlshifflett.wordpress.com/2010/11/07/in-the-box-ndash-mvvm-training/
sumber
Saya tahu ini adalah pertanyaan lama, tetapi ketika saya melakukan pencarian ini, saya menemukan banyak pertanyaan terkait, tetapi saya tidak menemukan jawaban yang benar-benar jelas. Jadi saya membuat implementasi kotak dialog / messagebox / popin saya sendiri, dan saya bagikan!
Saya pikir itu adalah "bukti MVVM", dan saya mencoba membuatnya sederhana dan tepat, tetapi saya baru di WPF, jadi jangan ragu untuk berkomentar, atau bahkan membuat permintaan tarik.
https://github.com/Plasma-Paris/Plasma.WpfUtils
Anda bisa menggunakannya seperti ini:
Atau seperti ini jika Anda ingin popin yang lebih canggih:
Dan itu menunjukkan hal-hal seperti ini:
sumber
Pendekatan standar
Setelah menghabiskan bertahun-tahun menangani masalah ini di WPF, saya akhirnya menemukan cara standar untuk mengimplementasikan dialog di WPF. Inilah keuntungan dari pendekatan ini:
Jadi apa kuncinya. Ini adalah DI + IoC .
Inilah cara kerjanya. Saya menggunakan MVVM Light, tetapi pendekatan ini juga dapat diperluas ke kerangka kerja lain:
Tambahkan antarmuka IDialogService ke proyek VM:
Mengekspos properti statis publik
IDialogService
jenis di AndaViewModelLocator
, tetapi biarkan bagian pendaftaran untuk lapisan Lihat untuk melakukan. Ini kuncinya .:Tambahkan implementasi antarmuka ini dalam proyek Aplikasi.
ShowMessage
,AskBooleanQuestion
dll.), Yang lain khusus untuk proyek ini dan menggunakan customWindow
. Anda dapat menambahkan lebih banyak jendela khusus dengan cara yang sama. Kuncinya adalah untuk menjaga elemen khusus UI di lapisan Lihat dan hanya mengekspos data yang dikembalikan menggunakan POCO di lapisan VM .Lakukan Pendaftaran IoC antarmuka Anda di lapisan Lihat menggunakan kelas ini. Anda dapat melakukan ini di konstruktor tampilan utama Anda (setelah
InitializeComponent()
panggilan):Ini dia. Anda sekarang memiliki akses ke semua fungsi dialog Anda di VM dan Lihat lapisan. Lapisan VM Anda dapat memanggil fungsi-fungsi ini seperti ini:
Fasilitas gratis lainnya
IDialogService
dalam proyek Uji Anda dan mendaftarkan kelas itu di IoC di konstruktor kelas tes Anda.Microsoft.Win32
untuk mengakses dialog Open and Save. Saya telah meninggalkan mereka karena ada juga versi WinForms dari dialog ini tersedia, ditambah seseorang mungkin ingin membuat versi mereka sendiri. Perhatikan juga bahwa beberapa pengenal yang digunakanDialogPresenter
adalah nama-nama windows saya sendiri (misSettingsWindow
.). Anda harus menghapusnya dari antarmuka dan implementasi atau menyediakan jendela Anda sendiri.DispatcherHelper.Initialize()
awal siklus hidup aplikasi Anda.Kecuali
DialogPresenter
yang disuntikkan di layer View, ViewModals lain harus didaftarkanViewModelLocator
dan kemudian properti statis publik dari tipe itu harus diekspos untuk dikonsumsi oleh layer View. Sesuatu seperti ini:Sebagian besar, dialog Anda seharusnya tidak memiliki kode-belakang untuk hal-hal seperti mengikat atau mengatur DataContext dll. Anda bahkan tidak boleh melewatkan hal-hal sebagai parameter konstruktor. XAML dapat melakukan itu semua untuk Anda, seperti ini:
DataContext
dengan cara ini memberi Anda semua jenis manfaat waktu-desain seperti Intellisense dan pelengkapan otomatis.Semoga itu bisa membantu semua orang.
sumber
Saya sedang merenungkan masalah yang sama ketika menanyakan bagaimana tampilan model untuk suatu tugas atau dialog .
Solusi saya saat ini terlihat seperti ini:
Ketika model tampilan memutuskan bahwa input pengguna diperlukan, itu menarik contoh
SelectionTaskModel
dengan pilihan yang mungkin bagi pengguna. Infrastruktur menangani memunculkan tampilan yang sesuai, yang pada waktu yang tepat akan memanggilChoose()
fungsi dengan pilihan pengguna.sumber
Saya berjuang dengan masalah yang sama. Saya telah menemukan cara untuk berkomunikasi antara View dan ViewModel. Anda dapat memulai mengirim pesan dari ViewModel ke View untuk mengatakannya untuk menampilkan kotak pesan dan itu akan melaporkan kembali dengan hasilnya. Kemudian ViewModel dapat merespons hasil yang dikembalikan dari View.
Saya menunjukkan ini di blog saya :
sumber
Saya telah menulis artikel yang cukup komprehensif tentang topik ini dan juga mengembangkan perpustakaan pop-in untuk Dialog MVVM. Kepatuhan terhadap MVVM tidak hanya mungkin tetapi sangat bersih bila diterapkan dengan benar, dan dapat dengan mudah diperluas ke perpustakaan pihak ketiga yang tidak mengikutinya sendiri:
https://www.codeproject.com/Articles/820324/Implementing-Dialog-Boxes-in-MVVM
sumber
Maaf, tetapi saya harus mengikuti. Saya telah melalui beberapa solusi yang disarankan, sebelum menemukan namespace Prism.Wpf.Interactivity dalam proyek Prism. Anda dapat menggunakan permintaan interaksi dan tindakan jendela popup untuk menggulung jendela kustom atau untuk kebutuhan sederhana ada dibangun di popup Pemberitahuan dan Konfirmasi. Ini menciptakan jendela yang benar dan dikelola seperti itu. Anda bisa melewatkan objek konteks dengan dependensi apa pun yang Anda butuhkan dalam dialog. Kami menggunakan solusi ini di tempat kerja saya sejak saya menemukannya. Kami memiliki banyak pengembang senior di sini dan tidak ada yang datang dengan sesuatu yang lebih baik. Solusi kami sebelumnya adalah layanan dialog menjadi overlay dan menggunakan kelas presenter untuk mewujudkannya, tetapi Anda harus memiliki pabrik untuk semua model dialog, dll.
Ini tidak sepele tetapi juga tidak super rumit. Dan itu dibangun untuk Prism dan karena itu yang terbaik (atau lebih baik) berlatih IMHO.
2 sen saya!
sumber
EDIT: ya saya setuju ini bukan pendekatan MVVM yang benar dan saya sekarang menggunakan sesuatu yang mirip dengan apa yang disarankan oleh blindmeis.
Salah satu cara Anda dapat melakukan ini adalah
Di Main View Model Anda (tempat Anda membuka modal):
Dan di Modal Window View / ViewModel Anda:
XAML:
ViewModel:
atau mirip dengan apa yang diposting di sini WPF MVVM: Cara menutup jendela
sumber