Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Ez a témakör áttekintést nyújt a Windows Presentation Foundation (WPF) és a Win32 kód együttműködéséről. A WPF gazdag környezetet biztosít az alkalmazások létrehozásához. Ha azonban jelentős befektetéssel rendelkezik a Win32-kódba, hatékonyabb lehet a kód egy részének újrafelhasználása.
A WPF és a Win32 együttműködésének alapjai
A WPF és a Win32 kód közötti együttműködésnek két alapvető technikája van.
WPF-tartalom elhelyezése egy Win32-ablakban. Ezzel a technikával a WPF fejlett grafikus képességeit használhatja egy szabványos Win32-ablak és alkalmazás keretein belül.
Win32-ablak beágyazása WPF-tartalomba. Ezzel a technikával egy meglévő egyéni Win32-vezérlőt használhat más WPF-tartalmak kontextusában, és adatokat továbbíthat a határokon.
Ezen technikák mindegyike fogalmilag be van vezetve ebben a témakörben. A WPF Win32-ben való üzemeltetésének kódorientáltabb illusztrációját a útmutatóban találja: WPF-tartalom üzemeltetése a Win32-ben. A Win32 WPF-ben való üzemeltetésének kódorientáltabb szemléltetéséért lásd útmutatót: Win32-vezérlő üzemeltetése a WPF.
WPF együttműködési projektek
A WPF API-k felügyelt kódnak számítanak, de a legtöbb meglévő Win32-program nem felügyelt C++ nyelven van megírva. A WPF API-kat nem hívhatja meg valódi, nem felügyelt programból. Ha azonban a /clr lehetőséget használja a Microsoft Visual C++ fordítóval, létrehozhat egy vegyes, felügyelt és nem felügyelt programot, ahol zökkenőmentesen keverheti a felügyelt és a nem felügyelt API-hívásokat.
Az egyik projektszintű bonyodalom az, hogy nem fordíthat XAML-fájlokat C++ projektbe. Ezt több projektmegosztási módszer is kompenzálja.
Hozzon létre egy C# DLL-t, amely lefordított szerelvényként tartalmazza az összes XAML-lapot, majd a C++ végrehajtható fájl hivatkozásként tartalmazza a DLL-t.
Hozzon létre egy C#-végrehajtható fájlt a WPF-tartalomhoz, és hivatkozzon rá egy C++ DLL-re, amely tartalmazza a Win32-tartalmat.
Az XAML összeállítása helyett használja a Load-t az XAML futásidőben történő betöltéséhez.
Ne használja egyáltalán az XAML-t, és írja meg az összes WPF-et kódban, majd állítsa össze az elemfát Application-tól kezdve.
Használjon bármilyen módszert, amely a legjobban megfelel Önnek.
Megjegyzés:
Ha korábban még nem használta a C++/CLI-t, előfordulhat, hogy néhány "új" kulcsszót, például gcnew és nullptr észlel az interoperációs kód példáiban. Ezek a kulcsszavak felülírják a régebbi dupla aláhúzásos szintaxist (__gc), és természetesebb szintaxist biztosítanak a C++-ban felügyelt kódhoz. A C++/CLI által felügyelt funkciókkal kapcsolatos további információkért tekintse meg futtatókörnyezeti platformok összetevőbővítményeit.
Hogyan használja a WPF a Hwnds-t?
A WPF "HWND interop" kihasználása érdekében tisztában kell lenni azzal, hogy a WPF hogyan használja a HWND-ket. A HWND-k esetében a WPF-renderelés nem keverhető DirectX-rendereléssel vagy GDI/GDI+ rendereléssel. Ennek számos következménye van. Elsősorban azért, hogy ezeket a renderelési modelleket egyáltalán össze lehessen keverni, létre kell hoznia egy interoperációs megoldást, és minden használni kívánt renderelési modellhez használnia kell az interoperáció kijelölt szegmenseit. A renderelési viselkedés emellett egy "légtérre" vonatkozó korlátozást is létrehoz arra vonatkozóan, amit az interoperációs megoldás el tud érni. A "légtér" fogalmát részletesebben Technológiai régiók áttekintésecímű témakörben ismertetik.
A képernyőn található összes WPF-elem végső soron egy HWND által van támogatva. WPF-Windowlétrehozásakor a WPF létrehoz egy legfelső szintű HWND-t, és egy HwndSource használatával helyezi el a Window és annak WPF-tartalmát a HWND-ben. Az alkalmazás többi WPF-tartalma ugyanazt az HWND-t használja. Kivételt képeznek a menük, a kombinált lista legördülő menüi és más előugró ablakok. Ezek az elemek létrehozzák a saját legfelső szintű ablakukat, ezért a WPF-menük esetleg túlléphetnek az azt tartalmazó HWND ablak szélén. Ha a HwndHost segítségével egy HWND-t helyez el a WPF-ben, a WPF tájékoztatja a Win32-t arról, hogyan helyezze el az új gyermek HWND-t a WPF Window HWND-hez képest.
A HWND-hez kapcsolódó fogalom az átláthatóság az egyes HWND-k között és azok között. Ezt a témakört Technológiai régiók áttekintésecímű témakörben is ismertetjük.
WPF-tartalom üzemeltetése Microsoft Win32-ablakban
A WPF Win32-ablakban való üzemeltetésének kulcsa a HwndSource osztály. Ez az osztály egy Win32-ablakban burkolja a WPF-tartalmat, így a WPF-tartalom gyermekablakként beépíthető a felhasználói felületbe. Az alábbi megközelítés egyetlen alkalmazásban egyesíti a Win32 és a WPF protokollt.
Implementálja a WPF-tartalmat (a tartalom gyökérelemét) felügyelt osztályként. Az osztály általában az egyik olyan osztálytól öröklődik, amely több gyermekelemet tartalmazhat, és/vagy gyökérelemként használható, például DockPanel vagy Page. A következő lépésekben ezt az osztályt WPF-tartalomosztálynak nevezzük, az osztály példányait pedig WPF-tartalomobjektumoknak nevezzük.
Windows-alkalmazás implementálása C++/CLI használatával. Ha egy meglévő, nem felügyelt C++ alkalmazással kezd, általában engedélyezheti a felügyelt kód meghívását úgy, hogy a projektbeállításokat úgy módosítja, hogy az tartalmazza a
/clrfordító jelölőt (a jelen témakörben nem ismertetjük, hogy mi szükséges/clrfordítás támogatásához).Állítsa a szálmodellt egyszálas lakásra (STA). A WPF ezt a szálmodellt használja.
A WM_CREATE értesítés kezelése az ablakos eljárásban.
A kezelőn belül (vagy egy függvényen belül, amelyet a kezelő hív) tegye a következőket:
Hozzon létre egy új HwndSource objektumot a HWND szülőablakmal
parentparaméterként.Hozzon létre egy példányt a WPF tartalom osztályból.
A WPF-tartalomobjektumra mutató hivatkozás hozzárendelése az HwndSource objektum RootVisual tulajdonsághoz.
Az HwndSource objektum Handle tulajdonsága tartalmazza az ablakkezelői fogantyút (HWND). Ha szeretne egy HWND-t, amelyet az alkalmazás nem felügyelt részében használhat, alakítsa át a
Handle.ToPointer()-t HWND-vé.
Olyan felügyelt osztály implementálása, amely egy statikus mezőt tartalmaz, amely a WPF-tartalomobjektumra mutató hivatkozást tartalmaz. Ez az osztály lehetővé teszi, hogy hivatkozzon a WPF-tartalomobjektumra a Win32-kódból, de ami még fontosabb, megakadályozza, hogy a HwndSource véletlenül szemetet gyűjtsön.
Értesítések fogadása a WPF tartalomobjektumból egy kezelő egy vagy több WPF-tartalomobjektum-eseményhez való csatolásával.
Kommunikáljon a WPF tartalomobjektummal a statikus mezőben tárolt hivatkozással tulajdonságok, hívási módszerek stb. beállításához.
Megjegyzés:
Ha külön könyvtárat hoz létre és hivatkozik rá, akkor az első lépéshez tartozó WPF-tartalomosztály definíciójának egy részét vagy egészét elvégezheti XAML-ben a tartalomosztály alapértelmezett részleges osztályának használatával. Bár általában egy Application objektumot is beilleszt az XAML összeállításakor egy modulba, valójában nem használja a Application-et az interoperáció részeként. Csak egy vagy több gyökér osztályt használ az alkalmazás által hivatkozott XAML-fájlokhoz, és részleges osztályaikra hivatkozik. Az eljárás hátralevő része lényegében a fent vázolthoz hasonló.
Ezeket a lépéseket a következő témakörben található kód szemlélteti, Útmutató: WPF-tartalom üzemeltetése a Win32-ben.
Microsoft Win32-ablak üzemeltetése a WPF-ben
A Win32-ablak más WPF-tartalmakon belüli üzemeltetésének kulcsa a HwndHost osztály. Ez az osztály egy WPF-elembe burkolja az ablakot, amely hozzáadható egy WPF-elemfához. HwndHost olyan API-kat is támogat, amelyek lehetővé teszik az olyan feladatok elvégzését, mint az üzenetek feldolgozása az üzemeltetett ablakhoz. Az alapművelet a következő:
Elemfát hozhat létre egy WPF-alkalmazáshoz (kód vagy jelölőnyelv használatával). Keressen egy megfelelő és megengedett pontot az elemfában, ahol a HwndHost implementáció gyermekelemként adható hozzá. A lépések hátralevő részében ezt az elemet tartalékelemnek nevezzük.
A HwndHost alapján hozzon létre egy, a Win32-tartalmat tartalmazó objektumot.
Ebben az osztályban írja felül a HwndHost metódust BuildWindowCore. Adja vissza a üzemeltetett ablak HWND azonosítóját. Előfordulhat, hogy a tényleges vezérlőelem(ek)et a visszaadott ablak gyermekablakaként szeretné becsomagolni; A vezérlők gazdaablakban való körbefuttatása egyszerű módot biztosít a WPF-tartalom számára, hogy értesítéseket kapjon a vezérlőktől. Ez a technika segít kijavítani néhány Win32-problémát az üzemeltetett vezérlőhatáron lévő üzenetkezeléssel kapcsolatban.
A HwndHost metódusok DestroyWindowCore és WndProcfelülírása. A cél itt az üzemeltetett tartalomra mutató hivatkozások feldolgozása és eltávolítása, különösen akkor, ha nem felügyelt objektumokra mutató hivatkozásokat hozott létre.
A kód mögötti fájlban hozza létre a vezérlő hosztoló osztály egy példányát, és tegye azt a fenntartó elem gyermekévé. Általában egy eseménykezelőt, például Loaded, vagy a részleges osztálykonstruktort használná. Az együttműködési tartalmat azonban futtatókörnyezeti viselkedéssel is hozzáadhatja.
A kijelölt ablaküzenetek, például a vezérlőértesítések feldolgozása. Két megközelítés létezik. Mindkettő azonos hozzáférést biztosít az üzenetstreamhez, így a választás nagyrészt a programozási kényelem kérdése.
A HwndHost metódus WndProcfelülbírálásával implementálhatja az összes üzenet üzenetének feldolgozását (nem csak leállítási üzeneteket).
A WPF gazdaelem az MessageHook esemény kezelésével dolgozza fel az üzeneteket. Ez az esemény minden olyan üzenetnél kiváltódik, amelyet a rendszer az üzemeltetett ablak főablak-eljárásának küld.
A WndProchasználatával nem lehet feldolgozni a folyamaton kívül lévő windowsos üzeneteket.
A nem felügyelt
SendMessagefüggvény meghívásához platformhívással kommunikáljon a üzemeltetett ablakkal.
Az alábbi lépések végrehajtásával létrehoz egy alkalmazást, amely az egér bemenetével működik. A IKeyboardInputSink felület implementálásával többlapos támogatást adhat a üzemeltetett ablakhoz.
Minden egyes lépést kódszemléltetéssel mutatjuk be a Téma : Útmutató a Win32-vezérlő befogadására a WPF-ben című részben.
Hwnds Inside WPF
A HwndHost speciális vezérlőként is felfogható. (Technikailag a HwndHost egy FrameworkElement származtatott osztály, nem pedig Control származtatott osztály, de az együttműködés szempontjából vezérlőnek tekinthető.) HwndHost az üzemeltetett tartalom mögöttes Win32-jellegét úgy absztrakciója, hogy a WPF fennmaradó része egy másik vezérlőszerű objektumnak tekinti az üzemeltetett tartalmat, amelynek renderelnie és feldolgoznia kell a bemenetet. HwndHost általában úgy viselkedik, mint bármely más WPF-FrameworkElement, bár a kimenet (rajz és grafika) és a bemenet (egér és billentyűzet) között vannak néhány fontos különbség a mögöttes HWND-k által támogatott korlátozások alapján.
A kimeneti viselkedés jelentős eltérései
FrameworkElement, amely az HwndHost alaposztály, számos olyan tulajdonsággal rendelkezik, amelyek a felhasználói felület módosítását jelentik. Ezek közé tartoznak az olyan tulajdonságok, mint a FrameworkElement.FlowDirection, amelyek szülőként módosítják az elem elemeinek elrendezését. Ezeknek a tulajdonságoknak a többsége azonban nem felel meg a lehetséges Win32-ekvivalenseknek, még akkor sem, ha léteznek ilyen egyenértékűek. Túl sok ilyen tulajdonság és azok jelentése túlzottan a renderelési technológiára specializált ahhoz, hogy a leképezések gyakorlatiasak legyenek. Ezért az olyan tulajdonságok beállítása, mint amilyen a FlowDirection a HwndHost-en, nincs hatással rá.
HwndHost nem forgatható, nem skálázható, nem nyújtható vagy más módon nem módosítható egy transzformáció által.
HwndHost nem támogatja a Opacity tulajdonságot (alfa-keverés). Ha a HwndHost tartalom alfainformációt tartalmazó System.Drawing műveleteket hajt végre, az önmagában nem szabálysértés, de a HwndHost egésze csak az Átlátszatlanságot támogatja = 1,0 (100%).
HwndHost megjelennek a többi WPF-elem tetején ugyanabban a felső szintű ablakban. A ToolTip vagy ContextMenu által létrehozott menü egy külön felső szintű ablak, és így helyesen fog viselkedni HwndHost-vel.
HwndHost nem veszi figyelembe a szülő UIElementkivágási régióját. Ez akkor lehet probléma, ha egy HwndHost osztályt próbál görgethető régióba vagy a(z) Canvas-be helyezni.
A bemeneti viselkedés jelentős eltérései
Általánosságban elmondható, hogy míg a bemeneti eszközök hatóköre a HwndHost üzemeltetett Win32-régión belül van, a bemeneti események közvetlenül a Win32-be kerülnek.
Amíg az egér a HwndHostfelett van, az alkalmazás nem fogad WPF egéreseményeket, és a WPF tulajdonság IsMouseOver értéke
falselesz.Amíg a HwndHost rendelkezik billentyűzetfókusszal, az alkalmazás nem fogad WPF billentyű-eseményeket, és a WPF tulajdonság IsKeyboardFocusWithin értéke
falselesz.Ha a fókusz a HwndHost-n belül van, és egy másik vezérlőre vált a HwndHost-en belül, az alkalmazás nem kapja meg a WPF-eseményeket GotFocus vagy LostFocus.
A kapcsolódó tolltulajdonságok és események hasonlóak, és nem jeleznek információt, amíg a toll HwndHostfölött van.
Tabulálás, Mnemonics és Gyorsbillentyűk
A IKeyboardInputSink és IKeyboardInputSite felületek lehetővé teszik, hogy zökkenőmentes billentyűzetfelületet hozzon létre vegyes WPF- és Win32-alkalmazásokhoz:
A Win32 és a WPF-összetevők közötti lapozás
Mnemonikák és gyorsítók, amelyek akkor is működnek, ha a fókusz egy Win32-összetevőn belül van, és ha egy WPF-összetevőn belül van.
A HwndHost és a HwndSource osztály egyaránt biztosítja a IKeyboardInputSinkimplementációit, de előfordulhat, hogy nem kezelik az összes olyan bemeneti üzenetet, amelyet speciálisabb forgatókönyvekhez szeretne használni. Írd felül a megfelelő metódusokat a kívánt billentyűzet viselkedésének eléréséhez.
A felületek csak azt támogatják, ami a WPF és a Win32 régió közötti átmenet során történik. A Win32-régióban a lapozási viselkedést teljes mértékben a Win32 által implementált, a lapozáshoz használt logika vezérli, ha van ilyen.
Lásd még
.NET Desktop feedback