Bagikan melalui


Interoperatur WPF dan Win32

Topik ini memberikan gambaran umum tentang cara mengoperasikan kode Windows Presentation Foundation (WPF) dan Win32. WPF menyediakan lingkungan yang kaya untuk membuat aplikasi. Namun, ketika Anda memiliki investasi besar dalam kode Win32, mungkin lebih efektif untuk menggunakan kembali beberapa kode tersebut.

Dasar-Dasar Interoperaksi WPF dan Win32

Ada dua teknik dasar untuk interoperarasi antara kode WPF dan Win32.

  • Host konten WPF di jendela Win32. Dengan teknik ini, Anda dapat menggunakan kemampuan grafis canggih WPF dalam kerangka kerja jendela dan aplikasi Win32 standar.

  • Host jendela Win32 dalam konten WPF. Dengan teknik ini, Anda dapat menggunakan kontrol Win32 kustom yang ada dalam konteks konten WPF lainnya, dan meneruskan data di seluruh batas.

Masing-masing teknik ini secara konseptual diperkenalkan dalam topik ini. Untuk ilustrasi yang lebih berorientasi kode untuk menghosting WPF di Win32, lihat Panduan: Hosting Konten WPF di Win32. Untuk ilustrasi yang lebih berorientasi kode untuk menghosting Win32 di WPF, lihat Panduan: Menghosting Kontrol Win32 di WPF.

Proyek Interoperabilitas WPF

API WPF adalah kode terkelola, tetapi sebagian besar program Win32 yang ada ditulis dalam C++yang tidak dikelola. Anda tidak dapat memanggil API WPF dari program benar yang tidak dikelola. Namun, dengan menggunakan /clr opsi dengan pengkompilasi Microsoft Visual C++, Anda dapat membuat program campuran yang tidak dikelola terkelola di mana Anda dapat dengan mulus mencampur panggilan API terkelola dan tidak terkelola.

Salah satu komplikasi tingkat proyek adalah Anda tidak dapat mengkompilasi file Extensible Application Markup Language (XAML) ke dalam proyek C++. Ada beberapa teknik pembagian proyek untuk mengimbangi hal ini.

  • Buat C# DLL yang berisi semua halaman XAML Anda sebagai rakitan yang dikompilasi, lalu minta C++ Anda dapat dieksekusi sertakan DLL tersebut sebagai referensi.

  • Buat C# yang dapat dieksekusi untuk konten WPF, dan mintalah untuk mereferensikan C++ DLL yang berisi konten Win32.

  • Gunakan Load untuk memuat XAML apa pun pada waktu proses, alih-alih mengkompilasi XAML Anda.

  • Jangan gunakan XAML sama sekali, dan tulis semua WPF Anda dalam kode, bangun pohon elemen dari Application.

Gunakan pendekatan apa pun yang paling sesuai untuk Anda.

Catatan

Jika Anda belum menggunakan C++/CLI sebelumnya, Anda mungkin melihat beberapa kata kunci "baru" seperti gcnew dan nullptr dalam contoh kode interoperabilitas. Kata kunci ini menggantikan sintaks double-underscore yang lebih lama (__gc) dan memberikan sintaks yang lebih alami untuk kode terkelola di C++. Untuk mempelajari selengkapnya tentang fitur terkelola C++/CLI, lihat Ekstensi Komponen untuk Platform Runtime.

Cara WPF Menggunakan Hwnds

Untuk memanfaatkan WPF "HWND interop", Anda perlu memahami bagaimana WPF menggunakan HWND. Untuk HWND apa pun, Anda tidak dapat mencampur penyajian WPF dengan penyajian DirectX atau rendering GDI / GDI+. Ini memiliki sejumlah implikasi. Terutama, untuk mencampur model penyajian ini sama sekali, Anda harus membuat solusi interoperabilitas, dan menggunakan segmen interoperabilitas yang ditunjuk untuk setiap model penyajian yang Anda pilih untuk digunakan. Selain itu, perilaku penyajian menciptakan pembatasan "ruang udara" untuk apa yang dapat dicapai solusi interoperaksi Anda. Konsep "ruang udara" dijelaskan secara lebih rinci dalam topik Gambaran Umum Wilayah Teknologi.

Semua elemen WPF di layar pada akhirnya didukung oleh HWND. Ketika Anda membuat WPF Window, WPF membuat HWND tingkat atas, dan menggunakan HwndSource untuk menempatkan Window dan konten WPF-nya di dalam HWND. Sisa konten WPF Anda dalam berbagi aplikasi yang tunggal HWND. Pengecualiannya adalah menu, drop-down kotak kombo, dan pop-up lainnya. Elemen-elemen ini membuat jendela tingkat atas mereka sendiri, itulah sebabnya menu WPF berpotensi melewati tepi jendela HWND yang berisinya. Ketika Anda menggunakan HwndHost untuk menempatkan HWND di dalam WPF, WPF memberi tahu Win32 cara memposisikan HWND anak baru relatif terhadap WPF Window HWND.

Konsep terkait HWND adalah transparansi di dalam dan di antara setiap HWND. Ini juga dibahas dalam topik Gambaran Umum Wilayah Teknologi.

Hosting Konten WPF di Jendela Microsoft Win32

Kunci untuk menghosting WPF di jendela Win32 adalah kelasnya HwndSource . Kelas ini membungkus konten WPF di jendela Win32, sehingga konten WPF dapat dimasukkan ke dalam UI Anda sebagai jendela anak. Pendekatan berikut menggabungkan Win32 dan WPF dalam satu aplikasi.

  1. Terapkan konten WPF Anda (elemen akar konten) sebagai kelas terkelola. Biasanya, kelas mewarisi dari salah satu kelas yang dapat berisi beberapa elemen anak dan/atau digunakan sebagai elemen akar, seperti DockPanel atau Page. Dalam langkah-langkah berikutnya, kelas ini disebut sebagai kelas konten WPF, dan instans kelas disebut sebagai objek konten WPF.

  2. Menerapkan aplikasi Windows dengan C++/CLI. Jika Anda memulai dengan aplikasi C++ yang tidak dikelola yang ada, Anda biasanya dapat mengaktifkannya untuk memanggil kode terkelola dengan mengubah pengaturan proyek Anda untuk menyertakan /clr bendera kompilator (cakupan lengkap dari apa yang mungkin diperlukan untuk mendukung /clr kompilasi tidak dijelaskan dalam topik ini).

  3. Atur model threading ke Single Threaded Apartment (STA). WPF menggunakan model utas ini.

  4. Tangani pemberitahuan WM_CREATE di prosedur jendela Anda.

  5. Dalam handler (atau fungsi yang dipanggil handler), lakukan hal berikut:

    1. Buat objek baru HwndSource dengan HWND jendela induk sebagai parameternya parent .

    2. Buat instans kelas konten WPF Anda.

    3. Tetapkan referensi ke objek konten WPF ke HwndSource properti objek RootVisual .

    4. Properti HwndSource objek Handle berisi handel jendela (HWND). Untuk mendapatkan HWND yang dapat Anda gunakan di bagian aplikasi yang tidak dikelola, transmisikan Handle.ToPointer() ke HWND.

  6. Terapkan kelas terkelola yang berisi bidang statis yang menyimpan referensi ke objek konten WPF Anda. Kelas ini memungkinkan Anda untuk mendapatkan referensi ke objek konten WPF dari kode Win32 Anda, tetapi yang lebih penting mencegah Anda HwndSource menjadi sampah yang dikumpulkan secara tidak sengaja.

  7. Terima pemberitahuan dari objek konten WPF dengan melampirkan handler ke satu atau beberapa peristiwa objek konten WPF.

  8. Berkomunikasi dengan objek konten WPF dengan menggunakan referensi yang Anda simpan di bidang statis untuk mengatur properti, metode panggilan, dll.

Catatan

Anda dapat melakukan beberapa atau semua definisi kelas konten WPF untuk Langkah Satu di XAML menggunakan kelas parsial default kelas konten, jika Anda menghasilkan rakitan terpisah lalu mereferensikannya. Meskipun Anda biasanya menyertakan Application objek sebagai bagian dari mengkompilasi XAML ke dalam perakitan, Anda tidak akhirnya menggunakannya Application sebagai bagian dari interoperaksi, Anda hanya menggunakan satu atau beberapa kelas akar untuk file XAML yang dimaksud oleh aplikasi dan mereferensikan kelas parsial mereka. Sisa prosedur pada dasarnya mirip dengan yang diuraikan di atas.

Masing-masing langkah ini diilustrasikan melalui kode dalam topik Panduan: Hosting Konten WPF di Win32.

Hosting Jendela Microsoft Win32 di WPF

Kunci untuk menghosting jendela Win32 dalam konten WPF lainnya adalah kelasnya HwndHost . Kelas ini membungkus jendela dalam elemen WPF yang dapat ditambahkan ke pohon elemen WPF. HwndHost juga mendukung API yang memungkinkan Anda melakukan tugas seperti pesan proses untuk jendela yang dihosting. Prosedur dasarnya adalah:

  1. Buat pohon elemen untuk aplikasi WPF (dapat melalui kode atau markup). Temukan titik yang sesuai dan diizinkan di pohon elemen tempat HwndHost implementasi dapat ditambahkan sebagai elemen turunan. Di sisa langkah-langkah ini, elemen ini disebut sebagai elemen reserving.

  2. Berasal dari HwndHost untuk membuat objek yang menyimpan konten Win32 Anda.

  3. Di kelas host tersebut HwndHost , ambil alih metode BuildWindowCore. Mengembalikan HWND dari jendela yang dihosting. Anda mungkin ingin membungkus kontrol aktual sebagai jendela anak dari jendela yang dikembalikan; membungkus kontrol di jendela host menyediakan cara sederhana bagi konten WPF Anda untuk menerima pemberitahuan dari kontrol. Teknik ini membantu memperbaiki beberapa masalah Win32 mengenai penanganan pesan di batas kontrol yang dihosting.

  4. Ambil alih HwndHost metode DestroyWindowCore dan WndProc. Niat di sini adalah untuk memproses pembersihan dan menghapus referensi ke konten yang dihosting, terutama jika Anda membuat referensi ke objek yang tidak dikelola.

  5. Dalam file code-behind Anda, buat instans kelas hosting kontrol dan jadikan itu anak dari elemen reserving. Biasanya Anda akan menggunakan penanganan aktivitas seperti Loaded, atau menggunakan konstruktor kelas parsial. Tetapi Anda juga dapat menambahkan konten interoperabilitas melalui perilaku runtime.

  6. Memproses pesan jendela yang dipilih, seperti pemberitahuan kontrol. Ada dua pendekatan. Keduanya menyediakan akses yang identik ke aliran pesan, jadi pilihan Anda sebagian besar adalah masalah kenyamanan pemrograman.

    • Terapkan pemrosesan pesan untuk semua pesan (bukan hanya mematikan pesan) dalam penimpaan HwndHost metode WndProcAnda .

    • Minta elemen WPF hosting memproses pesan dengan menangani MessageHook peristiwa. Kejadian ini dinaikkan untuk setiap pesan yang dikirim ke prosedur jendela utama jendela yang dihosting.

    • Anda tidak dapat memproses pesan dari jendela yang tidak dapat diproses menggunakan WndProc.

  7. Berkomunikasi dengan jendela yang dihosting dengan menggunakan pemanggilan platform untuk memanggil fungsi yang tidak dikelola SendMessage .

Mengikuti langkah-langkah ini membuat aplikasi yang berfungsi dengan input mouse. Anda dapat menambahkan dukungan tab untuk jendela yang dihosting dengan menerapkan IKeyboardInputSink antarmuka.

Masing-masing langkah ini diilustrasikan melalui kode dalam topik Panduan: Menghosting Kontrol Win32 di WPF.

Hwnds Inside WPF

Anda dapat menganggap HwndHost sebagai kontrol khusus. (Secara teknis, HwndHost adalah FrameworkElement kelas turunan, bukan Control kelas turunan, tetapi dapat dianggap sebagai kontrol untuk tujuan interoperaksi.) HwndHost mengabstraksi sifat Win32 yang mendasar dari konten yang dihosting sehingga sisa WPF menganggap konten yang dihosting menjadi objek seperti kontrol lain, yang harus merender dan memproses input. HwndHost umumnya bertingkah seperti WPF FrameworkElementlainnya, meskipun ada beberapa perbedaan penting seputar output (gambar dan grafis) dan input (mouse dan keyboard) berdasarkan batasan apa yang dapat didukung HWND yang mendasar.

Perbedaan Penting dalam Perilaku Output

  • FrameworkElement, yang merupakan HwndHost kelas dasar, memiliki beberapa properti yang menyiratkan perubahan pada UI. Ini termasuk properti seperti FrameworkElement.FlowDirection, yang mengubah tata letak elemen dalam elemen tersebut sebagai induk. Namun, sebagian besar properti ini tidak dipetakan ke kemungkinan setara Win32, bahkan jika setara tersebut mungkin ada. Terlalu banyak properti ini dan maknanya terlalu teknologi rendering khusus untuk pemetaan menjadi praktis. Oleh karena itu, mengatur properti seperti FlowDirection aktif HwndHost tidak berpengaruh.

  • HwndHost tidak dapat diputar, diskalakan, condong, atau dipengaruhi oleh Transformasi.

  • HwndHost tidak mendukung Opacity properti (pencamburan alfa). Jika konten di dalam HwndHost operasi melakukan System.Drawing yang menyertakan informasi alfa, itu sendiri bukan pelanggaran, tetapi HwndHost secara keseluruhan hanya mendukung Opacity = 1,0 (100%).

  • HwndHost akan muncul di atas elemen WPF lainnya di jendela tingkat atas yang sama. Namun, ToolTip menu atau ContextMenu yang dihasilkan adalah jendela tingkat atas yang terpisah, sehingga akan berulah dengan benar dengan HwndHost.

  • HwndHost tidak menghormati wilayah kliping induknya UIElement. Ini berpotensi menjadi masalah jika Anda mencoba menempatkan HwndHost kelas di dalam wilayah gulir atau Canvas.

Perbedaan Penting dalam Perilaku Input

  • Secara umum, sementara perangkat input dilingkup dalam HwndHost wilayah Win32 yang dihosting, peristiwa input langsung masuk ke Win32.

  • Sementara mouse melebihi HwndHost, aplikasi Anda tidak menerima peristiwa mouse WPF, dan nilai properti IsMouseOver WPF akan menjadi false.

  • HwndHost Meskipun memiliki fokus keyboard, aplikasi Anda tidak akan menerima peristiwa keyboard WPF dan nilai properti IsKeyboardFocusWithin WPF adalah false.

  • Ketika fokus berada dalam HwndHost dan perubahan pada kontrol lain di dalam HwndHost, aplikasi Anda tidak akan menerima peristiwa GotFocus WPF atau LostFocus.

  • Properti dan peristiwa stylus terkait bersifat analog, dan tidak melaporkan informasi saat stylus berakhir HwndHost.

Tabbing, Mnemonics, dan Akselerator

Antarmuka IKeyboardInputSink dan IKeyboardInputSite memungkinkan Anda untuk membuat pengalaman keyboard yang mulus untuk aplikasi WPF campuran dan Win32:

  • Tab antara komponen Win32 dan WPF

  • Mnemonics dan akselerator yang berfungsi baik ketika fokus berada dalam komponen Win32 dan ketika berada dalam komponen WPF.

Kelas HwndHost dan HwndSource keduanya menyediakan implementasi IKeyboardInputSink, tetapi mungkin tidak menangani semua pesan input yang Anda inginkan untuk skenario yang lebih canggih. Ambil alih metode yang sesuai untuk mendapatkan perilaku keyboard yang Anda inginkan.

Antarmuka hanya memberikan dukungan untuk apa yang terjadi pada transisi antara wilayah WPF dan Win32. Dalam wilayah Win32, perilaku tab sepenuhnya dikendalikan oleh logika yang diimplementasikan Win32 untuk tab, jika ada.

Baca juga