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 tentang hosting 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 yang sepenuhnya tidak dikelola. Namun, dengan menggunakan opsi /clr dengan pengkompilasi Microsoft Visual C++, Anda dapat membuat program campuran terkelola dan tidak terkelola di mana Anda dapat mencampur panggilan API terkelola dan tidak terkelola dengan mulus.

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 DLL C# yang mengandung semua halaman XAML Anda sebagai rakitan yang telah dikompilasi, lalu sertakan DLL tersebut sebagai referensi dalam file eksekusi C++ Anda.

  • Buat file eksekusi C# untuk konten WPF dan pastikan file tersebut mereferensikan DLL C++ 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.

Nota

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 garis bawah ganda 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. Pada dasarnya, untuk menggabungkan model penyajian ini, Anda harus membuat solusi interoperabilitas dan menggunakan segmen interoperabilitas yang ditunjuk untuk setiap model penyajian yang Anda pilih. 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 sebuah HWND. Ketika Anda membuat WPF Window, WPF akan membuat HWND tingkat atas, dan menggunakan HwndSource untuk menempatkan Window beserta konten WPF-nya di dalam HWND. Sisa konten WPF dalam aplikasi Anda berbagi satu HWND yang sama. Pengecualian adalah kotak kombo drop-down, menu, 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 ke dalam WPF, WPF memberi tahu Win32 bagaimana memposisikan HWND turunan yang baru relatif terhadap HWND WPF Window.

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

Hosting Konten WPF di Jendela Microsoft Win32

Kunci untuk menghosting WPF di jendela Win32 adalah kelas 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 bendera pengkompilasi /clr (cakupan lengkap dari apa yang mungkin diperlukan untuk mendukung kompilasi /clr tidak dijelaskan dalam topik ini).

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

  4. Tanganilah pemberitahuan WM_CREATE dalam prosedur jendela Anda.

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

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

    2. Buat instans kelas konten WPF Anda.

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

    4. Objek HwndSource properti Handle berisi handle 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 HwndSource Anda 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.

Nota

Anda dapat melakukan sebagian atau seluruh definisi kelas konten WPF untuk Langkah Satu di XAML menggunakan kelas parsial bawaan kelas konten, jika Anda membuat rakitan terpisah dan kemudian merujuknya. Meskipun Anda biasanya menyertakan objek Application sebagai bagian dari kompilasi XAML ke dalam assembly, Anda tidak akhirnya menggunakan Application tersebut sebagai bagian dari interoperasi; Anda hanya menggunakan satu atau beberapa kelas akar untuk file XAML yang dirujuk oleh aplikasi dan merujuk kelas parsialnya. Sisa prosedur pada dasarnya mirip dengan yang diuraikan di atas.

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

Menampung Jendela Microsoft Win32 di WPF

Kunci untuk menghosting jendela Win32 dalam konten WPF lainnya adalah kelas 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 memproses pesan 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 implementasi HwndHost dapat ditambahkan sebagai elemen turunan. Di sisa langkah-langkah ini, elemen ini disebut sebagai elemen reserving.

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

  3. Di kelas host tersebut, lakukan override pada metode HwndHostBuildWindowCore. 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. Ganti fungsi HwndHostDestroyWindowCore 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 pesan penghentian) dalam penimpaan metode HwndHost milik Anda WndProc.

    • Minta elemen WPF hosting memproses pesan dengan menangani peristiwa MessageHook. Kejadian ini dipicu untuk setiap pesan yang dikirim ke prosedur jendela utama dari 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 SendMessage yang tidak dikelola.

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

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

Hwnds Inside WPF

Anda dapat menganggap HwndHost sebagai kontrol khusus. (Secara teknis, HwndHost adalah kelas turunan FrameworkElement, bukan kelas turunan Control, 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 sebagai objek seperti kontrol lain, yang harus merender dan memproses input. HwndHost umumnya berfungsi seperti elemen WPF FrameworkElementlainnya, meskipun ada beberapa perbedaan penting terkait output (gambar dan grafis) serta input (mouse dan keyboard) berdasarkan batasan dari apa yang dapat didukung oleh HWND yang mendasarinya.

Perbedaan Penting dalam Perilaku Output

  • FrameworkElement, yang merupakan kelas dasar HwndHost, 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 dari properti-properti ini dan maknanya yang terlalu spesifik untuk teknologi rendering sehingga pemetaan menjadi tidak praktis. Oleh karena itu, mengatur properti seperti FlowDirection pada HwndHost tidak berpengaruh.

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

  • HwndHost tidak mendukung properti Opacity (campuran alfa). Jika konten di dalam HwndHost melakukan operasi 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, menu ToolTip atau ContextMenu yang dihasilkan adalah jendela tingkat atas yang terpisah, sehingga akan berfungsi dengan benar dengan HwndHost.

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

Perbedaan Penting dalam Perilaku Input

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

  • Meskipun mouse berada di atas HwndHost, aplikasi Anda tidak menerima peristiwa mouse WPF, dan nilai properti WPF IsMouseOver akan false.

  • Meskipun HwndHost memiliki fokus papan ketik, aplikasi Anda tidak akan menerima peristiwa papan ketik WPF dan nilai properti WPF IsKeyboardFocusWithin akan menjadi false.

  • Ketika fokus berada di HwndHost dan beralih ke kontrol lain di dalam HwndHost, aplikasi Anda tidak akan menerima event WPF GotFocus atau LostFocus.

  • Properti dan peristiwa stylus terkait bersifat serupa, dan tidak melaporkan informasi saat stylus berada di atas HwndHost.

Penggunaan Tab, Mnemoteknik, dan Akselerator

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

  • Melakukan tab antara komponen Win32 dan WPF

  • Mnemonik serta akselerator yang berfungsi, baik ketika fokus berada dalam komponen Win32 maupun ketika berada dalam komponen WPF.

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

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 diterapkan oleh Win32 untuk perilaku tab, jika ada.

Lihat juga