Lernprogramm: Hosten von visuellen Objekten in einer Win32-Anwendung
Windows Presentation Foundation (WPF) stellt eine umfangreiche Umgebung zum Erstellen von Anwendungen bereit. Wenn Sie allerdings bereits erhebliche Arbeit in das Schreiben von Win32-Code investiert haben, kann es effektiver sein, eine vorhandene Anwendung mit WPF zu erweitern, anstatt sie neu zu schreiben. Zur Unterstützung von Win32- und WPF-Grafiksubsystemen, die gleichzeitig in einer Anwendung verwendet werden, stellt WPF einen Mechanismus zum Hosten von Objekten in einem Win32-Fenster bereit.
In diesem Lernprogramm wird beschrieben, wie eine Beispielanwendung geschrieben wird (Beispiel für Treffertests mit Win32-Interoperabilität), die visuelle WPF-Objekte in einem Win32-Fenster hostet.
Dieses Thema enthält folgende Abschnitte.
- Anforderungen
- Erstellen des Host-Win32-Fensters
- Hinzufügen von visuellen Objekten zum Host-Win32-Fenster
- Implementieren des Win32-Nachrichtenfilters
- Verarbeiten der Win32-Nachrichten
- Verwandte Abschnitte
Anforderungen
In diesem Lernprogramm wird davon ausgegangen, dass Sie mit den Grundlagen der WPF-Programmierung und Win32-Programmierung vertraut sind. Eine Einführung in die Grundlagen der WPF-Programmierung finden Sie unter Exemplarische Vorgehensweise: Erste Schritte mit WPF. Eine Einführung in die Win32-Programmierung finden Sie in zahlreichen Büchern zu diesem Thema, insbesondere in Windows-Programmierung von Charles Petzold.
Hinweis |
---|
Dieses Lernprogramm schließt eine Reihe von Codebeispielen aus dem genannten Beispiel ein.Aus Gründen der besseren Lesbarkeit wird jedoch nicht der gesamte Beispielcode aufgeführt.Den vollständige Beispielcode finden Sie unter Beispiel für Treffertests mit Win32-Interoperabilität. |
Erstellen des Host-Win32-Fensters
Der Schlüssel zum Hosten von WPF-Objekten in einem Win32-Fenster ist die HwndSource-Klasse. Diese Klasse umschließt die WPF-Objekte mit einem Win32-Fenster, sodass sie als untergeordnetes Fenster in Ihre user interface (UI) eingebunden werden können.
Das folgende Beispiel zeigt den Code zum Erstellen des HwndSource-Objekts als Win32-Containerfenster für die visuellen Objekte. Verwenden Sie zum Festlegen des Fensterstils, der Position und anderer Parameter für das Win32-Fenster das HwndSourceParameters-Objekt.
' Constant values from the "winuser.h" header file.
Friend Const WS_CHILD As Integer = &H40000000, WS_VISIBLE As Integer = &H10000000
Friend Shared Sub CreateHostHwnd(ByVal parentHwnd As IntPtr)
' Set up the parameters for the host hwnd.
Dim parameters As New HwndSourceParameters("Visual Hit Test", _width, _height)
parameters.WindowStyle = WS_VISIBLE Or WS_CHILD
parameters.SetPosition(0, 24)
parameters.ParentWindow = parentHwnd
parameters.HwndSourceHook = New HwndSourceHook(AddressOf ApplicationMessageFilter)
' Create the host hwnd for the visuals.
myHwndSource = New HwndSource(parameters)
' Set the hwnd background color to the form's background color.
myHwndSource.CompositionTarget.BackgroundColor = System.Windows.Media.Brushes.OldLace.Color
End Sub
// Constant values from the "winuser.h" header file.
internal const int WS_CHILD = 0x40000000,
WS_VISIBLE = 0x10000000;
internal static void CreateHostHwnd(IntPtr parentHwnd)
{
// Set up the parameters for the host hwnd.
HwndSourceParameters parameters = new HwndSourceParameters("Visual Hit Test", _width, _height);
parameters.WindowStyle = WS_VISIBLE | WS_CHILD;
parameters.SetPosition(0, 24);
parameters.ParentWindow = parentHwnd;
parameters.HwndSourceHook = new HwndSourceHook(ApplicationMessageFilter);
// Create the host hwnd for the visuals.
myHwndSource = new HwndSource(parameters);
// Set the hwnd background color to the form's background color.
myHwndSource.CompositionTarget.BackgroundColor = System.Windows.Media.Brushes.OldLace.Color;
}
Hinweis |
---|
Der Wert der ExtendedWindowStyle-Eigenschaft kann nicht auf WS_EX_TRANSPARENT festgelegt werden.Dies bedeutet, dass das Host-Win32-Fenster nicht transparent sein kann.Aus diesem Grund wird als Hintergrundfarbe für das Host-Win32-Fenster die gleiche Hintergrundfarbe wie für das übergeordnete Fenster festgelegt. |
Hinzufügen von visuellen Objekten zum Host-Win32-Fenster
Nachdem Sie ein Host-Win32-Containerfenster für die visuellen Objekte erstellt haben, können Sie ihm visuelle Objekte hinzufügen. Sie müssen sicherstellen, dass Transformationen der visuellen Objekte, wie zum Beispiel Animationen, nicht über das Begrenzungsrechteck des Host-Win32-Fensters hinausgehen.
Das folgende Beispiel zeigt den Code zum Erstellen des HwndSource-Objekts und zum Hinzufügen von visuellen Objekten.
Hinweis |
---|
Die RootVisual-Eigenschaft des HwndSource-Objekts wird auf das erste visuelle Objekt festgelegt, das zum Host-Win32-Fenster hinzugefügt wird.Das visuelle Stammobjekt definiert den obersten Knoten der visuellen Objektstruktur.Alle weiteren visuellen Objekte, die dem Host-Win32-Fenster hinzugefügt werden, werden als untergeordnete Objekte hinzugefügt. |
Public Shared Sub CreateShape(ByVal parentHwnd As IntPtr)
' Create an instance of the shape.
Dim myShape As New MyShape()
' Determine whether the host container window has been created.
If myHwndSource Is Nothing Then
' Create the host container window for the visual objects.
CreateHostHwnd(parentHwnd)
' Associate the shape with the host container window.
myHwndSource.RootVisual = myShape
Else
' Assign the shape as a child of the root visual.
CType(myHwndSource.RootVisual, ContainerVisual).Children.Add(myShape)
End If
End Sub
public static void CreateShape(IntPtr parentHwnd)
{
// Create an instance of the shape.
MyShape myShape = new MyShape();
// Determine whether the host container window has been created.
if (myHwndSource == null)
{
// Create the host container window for the visual objects.
CreateHostHwnd(parentHwnd);
// Associate the shape with the host container window.
myHwndSource.RootVisual = myShape;
}
else
{
// Assign the shape as a child of the root visual.
((ContainerVisual)myHwndSource.RootVisual).Children.Add(myShape);
}
}
Implementieren des Win32-Nachrichtenfilters
Das Host-Win32-Fenster für visuelle Objekte erfordert eine Fenster-Nachrichtenfilterprozedur, um Nachrichten behandeln zu können, die von einer Anwendungswarteschlange an das Fenster gesendet werden. Die Fensterprozedur empfängt Nachrichten vom Win32-System. Hierbei kann es sich um Eingabenachrichten oder Nachrichten zur Fensterverwaltung handeln. Sie können optional eine Nachricht in der Fensterprozedur behandeln oder die Nachricht zur Standardverarbeitung an das System übergeben.
Das für visuelle Objekte als übergeordnetes Objekt definierte HwndSource-Objekt muss auf die Fenster-Nachrichtenfilterprozedur, die Sie bereitstellen, verweisen. Legen Sie beim Erstellen des HwndSource-Objekts die HwndSourceHook-Eigenschaft so fest, dass sie auf die Fensterprozedur verweist.
parameters.HwndSourceHook = New HwndSourceHook(AddressOf ApplicationMessageFilter)
parameters.HwndSourceHook = new HwndSourceHook(ApplicationMessageFilter);
Im folgenden Beispiel wird der Code zum Behandeln der Nachrichten für die linke und rechte Maustaste veranschaulicht. Der Koordinatenwert der Maustrefferposition ist im Wert des lParam-Parameters enthalten.
' Constant values from the "winuser.h" header file.
Friend Const WM_LBUTTONUP As Integer = &H202, WM_RBUTTONUP As Integer = &H205
Friend Shared Function ApplicationMessageFilter(ByVal hwnd As IntPtr, ByVal message As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr, ByRef handled As Boolean) As IntPtr
' Handle messages passed to the visual.
Select Case message
' Handle the left and right mouse button up messages.
Case WM_LBUTTONUP, WM_RBUTTONUP
Dim pt As New System.Windows.Point()
pt.X = CUInt(lParam) And CUInt(&HFFFF) ' LOWORD = x
pt.Y = CUInt(lParam) >> 16 ' HIWORD = y
MyShape.OnHitTest(pt, message)
End Select
Return IntPtr.Zero
End Function
// Constant values from the "winuser.h" header file.
internal const int WM_LBUTTONUP = 0x0202,
WM_RBUTTONUP = 0x0205;
internal static IntPtr ApplicationMessageFilter(
IntPtr hwnd, int message, IntPtr wParam, IntPtr lParam, ref bool handled)
{
// Handle messages passed to the visual.
switch (message)
{
// Handle the left and right mouse button up messages.
case WM_LBUTTONUP:
case WM_RBUTTONUP:
System.Windows.Point pt = new System.Windows.Point();
pt.X = (uint)lParam & (uint)0x0000ffff; // LOWORD = x
pt.Y = (uint)lParam >> 16; // HIWORD = y
MyShape.OnHitTest(pt, message);
break;
}
return IntPtr.Zero;
}
Verarbeiten der Win32-Nachrichten
Der Code im folgenden Beispiel veranschaulicht, wie ein Treffertest für die Hierarchie der visuellen Objekte, die im Host-Win32-Fenster enthalten sind, durchgeführt wird. Sie können ermitteln, ob sich ein Punkt in der Geometrie eines visuellen Objekts befindet, indem Sie die HitTest-Methode verwenden, um das visuelle Stammobjekt und den Koordinatenwert für den Treffertest anzugeben. In diesem Fall ist das visuelle Stammobjekt der Wert der RootVisual-Eigenschaft des HwndSource-Objekts.
' Constant values from the "winuser.h" header file.
Public Const WM_LBUTTONUP As Integer = &H0202, WM_RBUTTONUP As Integer = &H0205
' Respond to WM_LBUTTONUP or WM_RBUTTONUP messages by determining which visual object was clicked.
Public Shared Sub OnHitTest(ByVal pt As System.Windows.Point, ByVal msg As Integer)
' Clear the contents of the list used for hit test results.
hitResultsList.Clear()
' Determine whether to change the color of the circle or to delete the shape.
If msg = WM_LBUTTONUP Then
MyWindow.changeColor = True
End If
If msg = WM_RBUTTONUP Then
MyWindow.changeColor = False
End If
' Set up a callback to receive the hit test results enumeration.
VisualTreeHelper.HitTest(MyWindow.myHwndSource.RootVisual, Nothing, New HitTestResultCallback(AddressOf CircleHitTestResult), New PointHitTestParameters(pt))
' Perform actions on the hit test results list.
If hitResultsList.Count > 0 Then
ProcessHitTestResultsList()
End If
End Sub
// Constant values from the "winuser.h" header file.
public const int WM_LBUTTONUP = 0x0202,
WM_RBUTTONUP = 0x0205;
// Respond to WM_LBUTTONUP or WM_RBUTTONUP messages by determining which visual object was clicked.
public static void OnHitTest(System.Windows.Point pt, int msg)
{
// Clear the contents of the list used for hit test results.
hitResultsList.Clear();
// Determine whether to change the color of the circle or to delete the shape.
if (msg == WM_LBUTTONUP)
{
MyWindow.changeColor = true;
}
if (msg == WM_RBUTTONUP)
{
MyWindow.changeColor = false;
}
// Set up a callback to receive the hit test results enumeration.
VisualTreeHelper.HitTest(MyWindow.myHwndSource.RootVisual,
null,
new HitTestResultCallback(CircleHitTestResult),
new PointHitTestParameters(pt));
// Perform actions on the hit test results list.
if (hitResultsList.Count > 0)
{
ProcessHitTestResultsList();
}
}
Weitere Informationen über Treffertests für visuelle Objekte finden Sie unter Treffertests in der visuellen Ebene.
Siehe auch
Referenz
Konzepte
Treffertests in der visuellen Ebene