Spolupráce WPF a Win32
Toto téma obsahuje přehled spolupráce windows Presentation Foundation (WPF) a kódu Win32. WPF poskytuje bohaté prostředí pro vytváření aplikací. Pokud ale máte značné investice do kódu Win32, může být efektivnější použít některý z těchto kódů.
Základy spolupráce WPF a Win32
Existují dvě základní techniky pro spolupráci mezi kódem WPF a Win32.
Hostování obsahu WPF v okně Win32 Pomocí této techniky můžete použít pokročilé grafické funkce WPF v rámci standardního okna a aplikace Win32.
Hostování okna Win32 v obsahu WPF Pomocí této techniky můžete použít existující vlastní ovládací prvek Win32 v kontextu jiného obsahu WPF a předat data přes hranice.
Každá z těchto technik je koncepčně představena v tomto tématu. Další kódově orientované ilustrace hostování WPF v systému Win32 naleznete v tématu Návod: Hostování obsahu WPF v systému Win32. Další kódově orientované ilustrace hostování Win32 ve WPF naleznete v tématu Návod: Hostování ovládacího prvku Win32 v WPF.
Projekty spolupráce WPF
Rozhraní API WPF jsou spravovaný kód, ale většina stávajících programů Win32 je napsaná v nespravovaném jazyce C++. Z opravdu nespravovaného programu nelze volat rozhraní API WPF. Pomocí možnosti /clr
s kompilátorem Microsoft Visual C++ však můžete vytvořit smíšený nespravovaný program, ve kterém můžete bezproblémově kombinovat spravovaná a nespravovaná volání rozhraní API.
Jednou z komplikací na úrovni projektu je, že nelze kompilovat soubory XAML (Extensible Application Markup Language) do projektu C++. Existuje několik technik oddělení projektu, které by to kompenzovaly.
Vytvořte knihovnu DLL jazyka C#, která obsahuje všechny vaše stránky XAML jako kompilované sestavení, a potom přidejte tuto knihovnu DLL jako odkaz do spustitelného souboru C++.
Vytvořte spustitelný soubor jazyka C# pro obsah WPF a požádejte jej o odkaz na knihovnu DLL jazyka C++, která obsahuje obsah Win32.
Místo kompilace XAML použijte Load k načtení libovolného XAML za běhu.
Nepoužívejte XAML vůbec a veškerý váš WPF zapište v kódu, sestavte strom elementu z Application.
Používejte jakýkoli přístup, který vám nejlépe vyhovuje.
Poznámka
Pokud jste C++/CLI ještě nepoužívali, můžete si všimnout některých nových klíčových slov, jako jsou gcnew
a nullptr
v příkladech kódu spolupráce. Tato klíčová slova nahrazují starší syntaxi dvojitého podtržítka (__gc
) a poskytují přirozenější syntaxi pro spravovaný kód v jazyce C++. Další informace o spravovaných funkcích C++/CLI najdete v tématu Rozšíření komponent pro platformy runtime.
Jak WPF používá Hwnd
Chcete-li co nejlépe využít WPF "HWND interop", musíte pochopit, jak WPF používá HWND. Pro jakýkoli HWND nemůžete kombinovat vykreslování WPF s vykreslováním DirectX ani GDI / GDI+. To má řadu důsledků. Pokud chcete tyto modely vykreslování kombinovat, musíte především vytvořit řešení pro spolupráci a používat určené segmenty spolupráce pro každý model vykreslování, který se rozhodnete použít. Chování vykreslování také vytváří omezení "vzdušného prostoru" pro to, co může vaše řešení spolupráce dosáhnout. Koncept "vzdušného prostoru" je podrobněji vysvětlen v tématu Přehled technologických oblastí.
Všechny prvky WPF na obrazovce jsou nakonec založeny na HWND. Při vytváření WPF Window, WPF vytvoří okno nejvyšší úrovně HWND a používá HwndSource k umístění Window a jeho WPF obsahu uvnitř HWND. Zbytek obsahu WPF ve vaší aplikaci sdílí ten jednotný HWND. Výjimkou jsou nabídky, rozbalovací nabídky a další automaticky otevíraná okna. Tyto prvky vytvářejí vlastní okno nejvyšší úrovně, což je důvod, proč může nabídka WPF potenciálně jít přes okraj okna HWND, který ho obsahuje. Při použití HwndHost k vložení HWND do WPF informuje WPF systém Win32, jak umístit nový podřízený HWND vzhledem k HWND WPF Window.
Související koncept HWND je transparentnost uvnitř a mezi jednotlivými HWND. To je také popsáno v tématu Přehled technologické oblasti.
Hostování obsahu WPF v okně Microsoft Win32
Klíčem k hostování WPF v okně Win32 je třída HwndSource. Tato třída zabalí obsah WPF do okna Win32, aby bylo možné obsah WPF začlenit do uživatelského rozhraní jako podřízené okno. Následující přístup kombinuje Win32 a WPF v jedné aplikaci.
Implementujte obsah WPF (kořenový prvek obsahu) jako spravovanou třídu. Třída obvykle dědí z jedné z tříd, které mohou obsahovat více podřízených elementů a/nebo se používají jako kořenový prvek, například DockPanel nebo Page. V dalších krocích se tato třída označuje jako třída obsahu WPF a instance třídy jsou označovány jako objekty obsahu WPF.
Implementujte aplikaci pro Windows pomocí C++/CLI. Pokud začínáte s existující nespravovanou aplikací C++, můžete ji obvykle povolit volání spravovaného kódu změnou nastavení projektu tak, aby zahrnoval příznak kompilátoru
/clr
(úplný rozsah toho, co může být nezbytné k podpoře/clr
kompilace není popsáno v tomto tématu).Nastavte model threadingu na Jednovláknový byt (STA). WPF používá tento model vláken.
Zpracujte oznámení WM_CREATE v okně.
V rámci obslužné rutiny (nebo funkce, kterou obslužná rutina volá), postupujte takto:
Vytvořte nový objekt HwndSource s nadřazeným oknem HWND jako parametr
parent
.Vytvořte instanci třídy obsahu WPF.
Přiřaďte odkaz na WPF obsahový objekt vlastnosti RootVisual objektu HwndSource.
Vlastnost objektu HwndSourceHandle obsahuje popisovač okna (HWND). Chcete-li získat HWND, který můžete použít v nespravované části vaší aplikace, přetypujte
Handle.ToPointer()
na HWND.
Implementujte spravovanou třídu, která obsahuje statické pole, které obsahuje odkaz na objekt obsahu WPF. Tato třída umožňuje získat referenci na objekt obsahu WPF z vašeho kódu Win32, ale důležitější je, že tím zabrání, aby vaše HwndSource bylo neúmyslně uvolněno z paměti.
Přijímat oznámení z objektu obsahu WPF připojením obslužné rutiny k jedné nebo více událostem objektu obsahu WPF.
Komunikujte s objektem obsahu WPF pomocí odkazu, který jste uložili ve statickém poli k nastavení vlastností, volání metod atd.
Poznámka
Některé nebo všechny definice třídy obsahu WPF pro krok 1 v XAML můžete provést pomocí výchozí částečné třídy třídy obsahu, pokud vytvoříte samostatné sestavení a pak na něj odkazujete. Ačkoli obvykle zahrnete objekt Application jako součást kompilace XAML do sestavení, tento Application jako součást interoperace nepoužíváte. Stačí použít jednu nebo více kořenových tříd pro soubory XAML odkazované aplikací a využít jejich částečných tříd. Zbytek postupu je v podstatě podobný výše uvedenému postupu.
Každý z těchto kroků je ilustrován kódem v tématu Návod: Hostování obsahu WPF v systému Win32.
Hostování okna Microsoft Win32 ve WPF
Klíčem k hostování okna Win32 v rámci jiného obsahu WPF je třída HwndHost. Tato třída zabalí okno do elementu WPF, který lze přidat do stromu elementů WPF. HwndHost také podporuje rozhraní API, která umožňují provádět takové úlohy, jako jsou zpracování zpráv pro hostované okno. Základní postup je:
Vytvořte strom prvků pro aplikaci WPF (může být prostřednictvím kódu nebo značek). Vyhledejte vhodný a povolený bod ve stromu prvků, kde lze přidat HwndHost implementaci jako podřízený prvek. Ve zbývající části těchto kroků se tento prvek označuje jako prvek rezervace.
Proveďte odvození z HwndHost pro vytvoření objektu, který obsahuje vaši Win32 obsah.
V této třídě hostitele přepište metodu HwndHostBuildWindowCore. Vraťte HWND hostovaného okna. Skutečné ovládací prvky můžete chtít zabalit jako podřízené okno vráceného okna; zabalení ovládacích prvků v okně hostitele poskytuje jednoduchý způsob, jak obsah WPF přijímat oznámení z ovládacích prvků. Tato technika pomáhá opravit některé problémy Win32 týkající se zpracování zpráv na hranici hostovaného ovládacího prvku.
Přepište metody HwndHost, DestroyWindowCore a WndProc. Záměrem je zpracovat vyčištění a odebrat odkazy na hostovaný obsah, zejména pokud jste vytvořili odkazy na nespravované objekty.
V souboru s kódem vytvořte instanci třídy, která hostí ovládací prvek, a nastavte ji jako podřízený prvek hostitelského prvku. Obvykle byste použili obslužnou rutinu události, jako je Loaded, nebo použili konstruktor částečné třídy. Obsah interakce ale můžete také přidat prostřednictvím běhového chování.
Zpracování vybraných zpráv okna, jako jsou například řídicí oznámení. Existují dva přístupy. Oba poskytují identický přístup ke streamu zpráv, takže vaše volba je z velké části otázkou usnadnění programování.
Implementujte zpracování zpráv pro všechny zprávy (nejen vypínací zprávy) při přepisování metody HwndHostWndProc.
Nechte hostující prvek WPF zpracovat zprávy pomocí zpracování události MessageHook. Tato událost je vyvolána pro každou zprávu, která je odeslána do hlavního okna procedury hostovaného okna.
Zprávy z oken, které jsou mimo proces, nelze zpracovat pomocí WndProc.
Komunikujte s hostovaným oknem pomocí platformního vyvolání pro volání nespravované funkce
SendMessage
.
Pomocí těchto kroků vytvoříte aplikaci, která funguje se vstupem myši. Podporu tabbingu pro hostované okno můžete přidat implementací IKeyboardInputSink rozhraní.
Každý z těchto kroků je ilustrován kódem v tématu Návod: Hostování ovládacího prvku Win32 v WPF.
Hwnds uvnitř WPF
HwndHost si můžete představit jako zvláštní ovládací prvek. (Technicky vzato je HwndHostFrameworkElement odvozenou třídou, nikoli Control odvozenou třídou, ale lze ji považovat za kontrolu pro účely spolupráce.) HwndHost abstrahuje základní povahu hostovaného obsahu Win32 tak, aby zbývající část WPF považuje hostovaný obsah za jiný objekt podobný řízení, který by měl vykreslit a zpracovat vstup. HwndHost se obecně chová jako jakýkoli jiný FrameworkElementWPF , i když existují některé důležité rozdíly týkající se výstupu (kreslení a grafiky) a vstupu (myš a klávesnice) na základě omezení toho, co základní HWND může podporovat.
Důležité rozdíly ve výstupním chování
FrameworkElement, což je HwndHost základní třída, má poměrně málo vlastností, které naznačují změny uživatelského rozhraní. Patří mezi ně vlastnosti, jako je FrameworkElement.FlowDirection, které mění rozložení prvků v tomto prvku jako nadřazený prvek. Většina těchto vlastností však není mapována na možné ekvivalenty Win32, i když takové ekvivalenty mohou existovat. Příliš mnoho těchto vlastností a jejich významů je příliš specifické pro vykreslovací technologii, aby mapování bylo praktické. Nastavení vlastností, jako jsou FlowDirection na HwndHost, proto nemá žádný vliv.
HwndHost nelze otočit, škálovat, zkosit nebo jinak ovlivnit transformací.
HwndHost nepodporuje vlastnost Opacity (alfa blending). Pokud obsah uvnitř HwndHost provádí System.Drawing operace, které obsahují alfa informace, to není porušení, ale HwndHost jako celek podporuje pouze neprůhlednost = 1,0 (100%).
HwndHost se zobrazí nad ostatními prvky WPF ve stejném okně nejvyšší úrovně. Nicméně nabídka vygenerovaná ToolTip nebo ContextMenu je samostatné okno na nejvyšší úrovni, takže se bude chovat správně s HwndHost.
HwndHost nerespektuje oblast výřezu nadřazené UIElement. Mohlo by to být problém, pokud se pokusíte umístit třídu HwndHost do posuvné oblasti nebo Canvas.
Důležité rozdíly ve vstupním chování
Obecně platí, že i když jsou vstupní zařízení vymezená v rámci HwndHost hostované oblasti Win32, vstupní události přejdou přímo na Win32.
Pokud je kurzor myši nad HwndHost, vaše aplikace nepřijímá události myši WPF a proto hodnota vlastnosti WPF IsMouseOver bude
false
.Zatímco HwndHost má zaměření klávesnice, vaše aplikace nebude přijímat klávesové události WPF a hodnota vlastnosti WPF IsKeyboardFocusWithin bude
false
.Když je fokus v HwndHost a změní se na jiný ovládací prvek uvnitř HwndHost, aplikace neobdrží události WPF GotFocus ani LostFocus.
Související vlastnosti stylusu a události jsou analogické a neohlašují informace, zatímco stylus je nad HwndHost.
Tabulátory, Mnemonika a Zkratky
Rozhraní IKeyboardInputSink a IKeyboardInputSite umožňují vytvořit bezproblémové prostředí klávesnice pro smíšené aplikace WPF a Win32:
Přepínání mezi komponentami Win32 a WPF
Mnemoniky a akcelerátory, které fungují jak při zaostření v rámci komponenty Win32, tak i v komponentě WPF.
Třídy HwndHost a HwndSource poskytují implementace IKeyboardInputSink, ale nemusí zpracovávat všechny vstupní zprávy, které chcete pro pokročilejší scénáře. Přepište příslušné metody, abyste získali požadované chování klávesnice.
Rozhraní poskytují podporu pouze pro to, co se stane při přechodu mezi oblastmi WPF a Win32. V rámci oblasti Win32 je chování při přecházení zcela řízeno implementační logikou Win32 pro přechod, pokud nějaká existuje.
Viz také
.NET Desktop feedback