Delen via


Zelfstudie: Visual Objects hosten in een Win32-toepassing

Windows Presentation Foundation (WPF) biedt een uitgebreide omgeving voor het maken van toepassingen. Als u echter een aanzienlijke investering in Win32-code hebt, is het mogelijk effectiever om WPF-functionaliteit toe te voegen aan uw toepassing in plaats van uw code opnieuw te schrijven. WpF biedt ondersteuning voor Win32- en WPF-graphics-subsystemen die gelijktijdig worden gebruikt in een toepassing. WPF biedt een mechanisme voor het hosten van objecten in een Win32-venster.

In deze zelfstudie wordt beschreven hoe u een voorbeeldtoepassing schrijft, Hit Test met Win32 Interoperation Sample, die als host fungeert voor WPF-visualobjecten in een Win32-venster.

Behoeften

In deze zelfstudie wordt ervan uitgegaan dat u bekend bent met zowel WPF- als Win32-programmering. Zie Walkthrough: Mijn eerste WPF-bureaubladtoepassing voor een eenvoudige inleiding tot WPF-programmering. Voor een inleiding tot Win32 programmeren, zie een van de vele boeken over het onderwerp, in het bijzonder Programmeren van Windows door Charles Petzold.

Opmerking

Deze zelfstudie bevat een aantal codevoorbeelden uit het bijbehorende voorbeeld. Voor leesbaarheid bevat het echter niet de volledige voorbeeldcode. Zie Hit Test met Win32 Interoperation Sample voor de volledige voorbeeldcode.

Het Win32-hostvenster maken

De sleutel voor het hosten van WPF-objecten in een Win32-venster is de HwndSource klasse. Deze klasse verpakt de WPF-objecten in een Win32-venster, zodat ze als onderliggend venster in uw gebruikersinterface (UI) kunnen worden opgenomen.

In het volgende voorbeeld ziet u de code voor het maken van het HwndSource object als het Win32-containervenster voor de visuele objecten. Als u de vensterstijl, positie en andere parameters voor het Win32-venster wilt instellen, gebruikt u het HwndSourceParameters object.

// 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;
}
' 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

Opmerking

De waarde van de ExtendedWindowStyle eigenschap kan niet worden ingesteld op WS_EX_TRANSPARENT. Dit betekent dat het Win32-hostvenster niet transparant kan zijn. Daarom is de achtergrondkleur van het Win32-hostvenster ingesteld op dezelfde achtergrondkleur als het bovenliggende venster.

Visuele objecten toevoegen aan het Venster Host Win32

Zodra u een Host Win32-containervenster voor de visuele objecten hebt gemaakt, kunt u er visuele objecten aan toevoegen. U wilt ervoor zorgen dat transformaties van de visuele objecten, zoals animaties, niet verder gaan dan de grenzen van de begrenzingsrechthoek van het Win32-hostvenster.

In het volgende voorbeeld ziet u de code voor het maken van het HwndSource object en het toevoegen van visuele objecten.

Opmerking

De RootVisual eigenschap van het HwndSource object is ingesteld op het eerste visuele object dat is toegevoegd aan het Win32-venster van de host. Het visuele hoofdknooppunt definieert het bovenste knooppunt van de visuele objectenboom. Alle volgende visuele objecten die aan het Win32-hostvenster worden toegevoegd, worden toegevoegd als onderliggende objecten.

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);
    }
}
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

Het Win32-berichtfilter implementeren

Voor het Win32-hostvenster voor de visuele objecten is een filterprocedure voor vensterberichten vereist voor het verwerken van berichten die vanuit de toepassingswachtrij naar het venster worden verzonden. De vensterprocedure ontvangt berichten van het Win32-systeem. Dit kunnen invoerberichten of berichten voor vensterbeheer zijn. U kunt desgewenst een bericht in uw vensterprocedure afhandelen of het bericht doorgeven aan het systeem voor standaardverwerking.

Het HwndSource object dat u hebt gedefinieerd als het bovenliggende object voor de visuele objecten, moet verwijzen naar de filterprocedure voor vensterberichten die u opgeeft. Wanneer u het HwndSource object maakt, stelt u de HwndSourceHook eigenschap in om te verwijzen naar de vensterprocedure.

parameters.HwndSourceHook = new HwndSourceHook(ApplicationMessageFilter);
parameters.HwndSourceHook = New HwndSourceHook(AddressOf ApplicationMessageFilter)

In het volgende voorbeeld ziet u de code voor het verwerken van de berichten met de linker- en rechtermuisknop omhoog. De coördinaatwaarde van de positie van de muis bevindt zich in de waarde van de lParam parameter.

// 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;
}
' 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

De Win32-berichten verwerken

De code in het volgende voorbeeld laat zien hoe een hittest wordt uitgevoerd op basis van de hiërarchie van visuele objecten in het Win32-hostvenster. U kunt bepalen of een punt zich in de geometrie van een visueel object bevindt met behulp van de HitTest methode om het hoofdvisualobject en de coördinaatwaarde op te geven waarop moet worden getest. In dit geval is het hoofdvisuale object de waarde van de RootVisual-eigenschap van het HwndSource-object.

// 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();
    }
}
' 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

Zie Hit Testing in de Visual Layer voor meer informatie over raaktesten bij visuele objecten.

Zie ook