Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Dieses Thema enthält eine Übersicht über die Interoperabilität von Windows Presentation Foundation (WPF) und Win32-Code. WPF bietet eine umfangreiche Umgebung zum Erstellen von Anwendungen. Wenn Sie jedoch eine erhebliche Investition in Win32-Code haben, ist es möglicherweise effektiver, einige dieser Code wiederzuverwenden.
Grundlagen der WPF- und Win32-Interoperabilität
Es gibt zwei grundlegende Techniken für die Interoperabilität zwischen WPF- und Win32-Code.
Hosten von WPF-Inhalten in einem Win32-Fenster. Mit dieser Technik können Sie die erweiterten Grafikfunktionen von WPF im Rahmen eines Win32-Standardfensters und einer Standardanwendung verwenden.
Hosten eines Win32-Fensters in WPF-Inhalten. Mit dieser Technik können Sie ein vorhandenes benutzerdefiniertes Win32-Steuerelement im Kontext anderer WPF-Inhalte verwenden und Daten über die Grenzen hinweg übergeben.
Jede dieser Techniken wird konzeptionell in diesem Thema eingeführt. Eine codeorientiertere Abbildung des Hostens von WPF in Win32 finden Sie unter Walkthrough: Hosting WPF Content in Win32. Eine codeorientiertere Darstellung des Hostings von Win32 in WPF finden Sie unter Walkthrough: Hosting a Win32 Control in WPF.
WPF-Interoperabilitätsprojekte
WPF-APIs sind verwalteter Code, aber die meisten vorhandenen Win32-Programme werden in nicht verwaltetem C++ geschrieben. Sie können WPF-APIs nicht aus einem echten nicht verwalteten Programm aufrufen. Mithilfe der /clr
Option mit dem Microsoft Visual C++-Compiler können Sie jedoch ein gemischtes, nicht verwaltetes Programm erstellen, in dem Sie verwaltete und nicht verwaltete API-Aufrufe nahtlos kombinieren können.
Eine Komplikation auf Projektebene besteht darin, dass Sie extensible Application Markup Language (XAML)-Dateien nicht in ein C++-Projekt kompilieren können. Dafür gibt es mehrere Projektteilungstechniken.
Erstellen Sie eine C#-DLL, die alle XAML-Seiten als kompilierte Assembly enthält, und lassen Sie dann die ausführbare Datei C++ diese DLL als Referenz enthalten.
Erstellen Sie eine ausführbare C#-Datei für den WPF-Inhalt, und verweisen Sie auf eine C++-DLL, die den Win32-Inhalt enthält.
Verwenden Sie Load, um Ihre XAML-Dateien zur Laufzeit zu laden, anstatt sie zu kompilieren.
Verwenden Sie überhaupt keinen XAML-Code, und schreiben Sie den gesamten WPF im Code, und erstellen Sie die Elementstruktur aus Application.
Verwenden Sie den für Sie am besten geeigneten Ansatz.
Hinweis
Falls Sie C++/CLI bisher nicht verwendet haben, fällt Ihnen möglicherweise im Interop-Codebeispiel einige "neue" Schlüsselwörter wie gcnew
und nullptr
auf. Diese Schlüsselwörter ersetzen die ältere Syntax mit doppeltem Unterstrich (__gc
) und stellen eine natürlichere Syntax für verwalteten Code in C++ bereit. Weitere Informationen zu den verwalteten C++/CLI-Features finden Sie unter Komponentenerweiterungen für Runtime-Plattformen.
So verwendet WPF Hwnds
Um WPF "HWND interop" optimal zu nutzen, müssen Sie verstehen, wie WPF HWNDs verwendet. Für jedes HWND darf man das WPF-Rendering nicht mit DirectX-Rendering oder GDI/GDI+-Rendering kombinieren. Dies hat eine Reihe von Auswirkungen. Um diese Renderingmodelle überhaupt zu kombinieren, müssen Sie eine Interoperationslösung erstellen und bestimmte Segmente der Interoperabilität für jedes renderingmodell verwenden, das Sie verwenden möchten. Außerdem erstellt das Renderingverhalten eine "Luftraumeinschränkung" für die Interoperabilitätslösung. Das Konzept "Luftraum" wird im Thema Technologieregionenübersicht ausführlicher erläutert.
Alle WPF-Elemente auf dem Bildschirm werden letztendlich von einem HWND unterstützt. Wenn Sie einen WPF erstellen, erstellt WPF Windoweinen HWND auf oberster Ebene und verwendet einen HwndSource , um den Window WPF-Inhalt in der HWND zu platzieren. Der Rest des WPF-Inhalts in der Anwendung teilt dieses einzelne HWND. Eine Ausnahme sind Menüs, Kombinationsfeld-Dropdowns und andere Popups. Diese Elemente erstellen ein eigenes Fenster auf oberster Ebene. Deshalb kann ein WPF-Menü möglicherweise über den Rand des Fensters HWND hinausgehen, das es enthält. Wenn Sie HwndHost einen HWND in WPF einfügen, informiert WPF Win32, wie der neue untergeordnete HWND relativ zum WPF Window HWND positioniert wird.
Ein verwandtes Konzept zu HWND ist die Transparenz innerhalb und zwischen den einzelnen HWNDs. Dies wird auch im Thema Technologieregionen Overview erläutert.
Hosten von WPF-Inhalten in einem Microsoft Win32-Fenster
Der Schlüssel zum Hosten eines WPF in einem Win32-Fenster ist die HwndSource Klasse. Diese Klasse umschließt den WPF-Inhalt in einem Win32-Fenster, sodass der WPF-Inhalt als untergeordnetes Fenster in die Benutzeroberfläche integriert werden kann. Der folgende Ansatz kombiniert win32 und WPF in einer einzigen Anwendung.
Implementieren Sie Ihren WPF-Inhalt (das Inhaltsstammelement) als verwaltete Klasse. In der Regel erbt die Klasse von einer der Klassen, die mehrere untergeordnete Elemente enthalten können und/oder als Wurzelelement verwendet werden, wie z. B. DockPanel oder Page. In nachfolgenden Schritten wird diese Klasse als WPF-Inhaltsklasse bezeichnet, und Instanzen der Klasse werden als WPF-Inhaltsobjekte bezeichnet.
Implementieren Sie eine Windows-Anwendung mit C++/CLI. Wenn Sie mit einer vorhandenen nicht verwalteten C++-Anwendung beginnen, können Sie es in der Regel aktivieren, um verwalteten Code aufzurufen, indem Sie Die Projekteinstellungen so ändern, dass sie das
/clr
Compilerflagge enthalten (der vollständige Umfang, der erforderlich sein kann, um die Kompilierung zu unterstützen/clr
, wird in diesem Thema nicht beschrieben).Legen Sie das Threadingmodell auf Single Threaded Apartment (STA) fest. WPF verwendet dieses Threadingmodell.
Behandeln Sie die WM_CREATE-Benachrichtigung in Ihrer Fensterprozedur.
Führen Sie innerhalb des Handlers (oder einer Funktion, die der Handler aufruft) die folgenden Schritte aus:
Erstellen Sie ein neues HwndSource-Objekt und verwenden Sie das übergeordnete Fenster-HWND als
parent
-Parameter.Erstellen Sie eine Instanz Ihrer WPF-Inhaltsklasse.
Weisen Sie dem WPF-Inhaltsobjekt HwndSource einen Verweis auf die Objekteigenschaft RootVisual zu.
Die HwndSource Objekteigenschaft Handle enthält den Fenstergriff (HWND). Um einen HWND zu erhalten, den Sie im nicht verwalteten Teil Ihrer Anwendung verwenden können, wandeln Sie
Handle.ToPointer()
in ein HWND um.
Implementieren Sie eine verwaltete Klasse, die ein statisches Feld enthält, das einen Verweis auf Ihr WPF-Inhaltsobjekt enthält. Mit dieser Klasse können Sie einen Verweis auf das WPF-Inhaltsobjekt aus dem Win32-Code abrufen, aber was noch wichtiger ist, sie verhindert, dass Ihr HwndSource versehentlich der Garbage Collection zum Opfer fällt.
Empfangen von Benachrichtigungen vom WPF-Inhaltsobjekt durch Anfügen eines Handlers an eines oder mehrere der WPF-Inhaltsobjektereignisse.
Kommunizieren Sie mit dem WPF-Inhaltsobjekt mithilfe des Verweises, den Sie im statischen Feld gespeichert haben, um Eigenschaften, Aufrufmethoden usw. festzulegen.
Hinweis
Sie können einige oder alle WPF-Inhaltsklassendefinitionen für Schritt 1 in XAML mithilfe der Standardteilklasse der Inhaltsklasse ausführen, wenn Sie eine separate Assembly erstellen und dann darauf verweisen. Obwohl Sie in der Regel ein Application Objekt als Teil der Kompilierung des XAML-Codes in eine Assembly einschließen, verwenden Sie dies Application nicht als Teil der Interoperabilität, sie verwenden lediglich eine oder mehrere Stammklassen für XAML-Dateien, auf die von der Anwendung verwiesen wird, und verweisen auf ihre Teilklassen. Der Rest des Verfahrens ähnelt im Wesentlichen dem oben beschriebenen Verfahren.
Jede dieser Schritte wird durch Code im Thema Exemplarische Vorgehensweise: Hosten von WPF-Inhalten in Win32 veranschaulicht.
Hosten eines Microsoft Win32-Fensters in WPF
Der Schlüssel zum Hosten eines Win32-Fensters in anderen WPF-Inhalten ist die HwndHost Klasse. Diese Klasse umschließt das Fenster in einem WPF-Element, das einer WPF-Elementstruktur hinzugefügt werden kann. HwndHost unterstützt auch APIs, mit denen Sie Aufgaben wie Verarbeiten von Nachrichten für das gehostete Fenster ausführen können. Die grundlegende Prozedur lautet wie folgt:
Erstellen Sie eine Elementstruktur für eine WPF-Anwendung (kann über Code oder Markup erfolgen). Suchen Sie einen geeigneten und zulässigen Punkt in der Elementstruktur, an dem die HwndHost Implementierung als untergeordnetes Element hinzugefügt werden kann. Im weiteren Verlauf dieser Schritte wird dieses Element als Reservierungselement bezeichnet.
Leiten Sie von HwndHost ab, um ein Objekt zu erstellen, das Ihren Win32-Inhalt enthält.
Überschreiben Sie in dieser Hostklasse die HwndHost Methode BuildWindowCore. Gibt den HWND des gehosteten Fensters zurück. Möglicherweise möchten Sie das tatsächliche Steuerelement(n) als untergeordnetes Fenster des zurückgegebenen Fensters umschließen. Das Umschließen der Steuerelemente in einem Hostfenster bietet eine einfache Möglichkeit, wie WPF-Inhalte Benachrichtigungen von den Steuerelementen empfangen können. Diese Technik hilft, einige Win32-Probleme bei der Nachrichtenbehandlung an der Grenze des gehosteten Steuerelements zu beheben.
Überschreiben Sie die HwndHost Methoden DestroyWindowCore und WndProc. Dies ist die Absicht, Verweise auf den gehosteten Inhalt zu bereinigen und zu entfernen, insbesondere wenn Sie Verweise auf nicht verwaltete Objekte erstellt haben.
Erstellen Sie in Ihrer Code-Behind-Datei eine Instanz der Steuerelement-Hosting-Klasse und machen Sie sie zu einem untergeordneten Element des reservierten Elements. In der Regel verwenden Sie einen Ereignishandler wie Loaded oder den partiellen Klassenkonstruktor. Sie können den Interoperabilitätsinhalt aber auch über ein Laufzeitverhalten hinzufügen.
Ausgewählte Fensternachrichten verarbeiten, z. B. Steuerelementbenachrichtigungen. Es gibt zwei Verfahrensweisen. Beide bieten identischen Zugriff auf den Nachrichtendatenstrom, daher ist Ihre Wahl weitgehend eine Frage der Programmierfreundlichkeit.
Implementieren Sie die Nachrichtenverarbeitung für alle Nachrichten (nicht nur Herunterfahren von Nachrichten) in Ihrer Außerkraftsetzung der HwndHost Methode WndProc.
Lassen Sie das hostende WPF-Element die Nachrichten verarbeiten, indem Sie das MessageHook Ereignis behandeln. Dieses Ereignis wird für jede Nachricht ausgelöst, die an die Hauptfensterprozedur des gehosteten Fensters gesendet wird.
Sie können Nachrichten aus Fenstern, die sich außerhalb des Prozesses befinden, nicht mit WndProc verarbeiten.
Kommunizieren Sie mit dem gehosteten Fenster mithilfe des Plattformaufrufs, um die nicht verwaltete
SendMessage
Funktion aufzurufen.
Wenn Sie diese Schritte ausführen, wird eine Anwendung erstellt, die mit Mauseingaben funktioniert. Sie können die Tabulatorunterstützung für Ihr gehostetes Fenster hinzufügen, indem Sie die IKeyboardInputSink Schnittstelle implementieren.
Jede dieser Schritte wird durch Code im Thema Exemplarische Vorgehensweise veranschaulicht: Hosten eines Win32-Steuerelements in WPF.
Hwnds innerhalb von WPF
Sie können sich ein spezielles Steuerelement vorstellen HwndHost . (Technisch gesehen ist HwndHost eine von FrameworkElement abgeleitete Klasse und keine von Control abgeleitete Klasse. Sie kann jedoch im Hinblick auf die Interoperabilität als Steuerelement betrachtet werden.) HwndHost abstrahiert die zugrunde liegende Win32-Natur des gehosteten Inhalts, sodass der Rest von WPF den gehosteten Inhalt als ein weiteres, steuerelementähnliches Objekt betrachtet, das Eingaben rendern und verarbeiten soll. HwndHost verhält sich im Allgemeinen wie jeder andere WPF FrameworkElement, obwohl es einige wichtige Unterschiede bei der Ausgabe (Zeichnung und Grafik) und Eingabe (Maus und Tastatur) gibt, basierend auf Einschränkungen der zugrunde liegenden HWNDs.
Wichtige Unterschiede beim Ausgabeverhalten
FrameworkElement, was die HwndHost Basisklasse ist, verfügt über einige Eigenschaften, die Änderungen an der Benutzeroberfläche bedeuten. Dazu gehören Eigenschaften wie FrameworkElement.FlowDirection, die das Layout von Elementen innerhalb dieses Elements als übergeordnetes Element ändern. Die meisten dieser Eigenschaften sind jedoch nicht möglichen Win32-Entsprechungen zugeordnet, auch wenn solche Entsprechungen vorhanden sein könnten. Zu viele dieser Eigenschaften und ihre Bedeutungen sind zu rendering-technologiebezogen, um praktische Zuordnungen zu ermöglichen. Daher hat das Festlegen von Eigenschaften wie FlowDirection auf HwndHost keine Auswirkung.
HwndHost kann nicht gedreht, skaliert, verzerrt oder anderweitig von einer Transformation beeinflusst werden.
HwndHost unterstützt die Eigenschaft Opacity (Alphamischung) nicht. de-DE: Wenn Inhalte innerhalb des HwndHostSystem.Drawing-Operationen ausführen, die Alphainformationen enthalten, ist dies an sich kein Verstoß, aber das gesamte HwndHost unterstützt nur Opacity = 1,0 (100%).
HwndHost wird oberhalb anderer WPF-Elemente im selben Fenster angezeigt. Ein ToolTip- oder ContextMenu-generiertes Menü ist jedoch ein separates oberstes Fenster und verhält sich daher korrekt mit HwndHost.
HwndHost berücksichtigt den Beschneidungsbereich des übergeordneten Elements UIElement nicht. Dies ist möglicherweise ein Problem, wenn Sie versuchen, eine HwndHost Klasse in einen Bildlaufbereich oder Canvas zu setzen.
Wichtige Unterschiede beim Eingabeverhalten
Während Eingabegeräte im Allgemeinen innerhalb der HwndHost gehosteten Win32-Region festgelegt sind, gehen Eingabeereignisse direkt zu Win32.
Während sich die Maus über HwndHost befindet, empfängt Ihre Anwendung keine WPF-Mausereignisse, und der Wert der WPF-Eigenschaft IsMouseOver ist
false
.Während der HwndHost Tastaturfokus besteht, empfängt Ihre Anwendung keine WPF-Tastaturereignisse, und der Wert der WPF-Eigenschaft IsKeyboardFocusWithin lautet
false
.Wenn sich der Fokus innerhalb des HwndHost-Steuerelements befindet und sich zu einem anderen Steuerelement innerhalb des HwndHost ändert, empfängt Ihre Anwendung nicht die WPF-Ereignisse GotFocus oder LostFocus.
Verwandte Stifteigenschaften und -ereignisse sind analog und melden keine Informationen, während sich der Stift über HwndHost befindet.
Tabbing, Mnemonics und Accelerators
Die Schnittstellen IKeyboardInputSink und IKeyboardInputSite ermöglichen Ihnen, eine nahtlose Tastaturerfahrung für gemischte WPF- und Win32-Anwendungen zu schaffen.
Wechsel zwischen Win32- und WPF-Komponenten über die Tab-Taste
Mnemonics und Zugriffstasten, die sowohl in einer Win32-Komponente als auch in einer WPF-Komponente funktionieren.
Die HwndHost- und HwndSource-Klassen bieten beide Implementierungen von IKeyboardInputSink, könnten jedoch möglicherweise nicht alle Eingabemeldungen behandeln, die Sie eventuell für komplexere Szenarien benötigen. Überschreiben Sie die entsprechenden Methoden, um das gewünschte Tastaturverhalten zu erhalten.
Die Schnittstellen bieten nur Unterstützung für den Übergang zwischen den WPF- und Win32-Regionen. Innerhalb der Win32-Region wird das Tabbing-Verhalten vollständig durch die von Win32 implementierte Logik für das Tabbing gesteuert, sofern vorhanden.
Siehe auch
.NET Desktop feedback