Dela via


Självstudie: Hantera visuella objekt i ett Win32-program

Windows Presentation Foundation (WPF) ger en omfattande miljö för att skapa program. Men när du har en betydande investering i Win32-kod kan det vara mer effektivt att lägga till WPF-funktioner i ditt program i stället för att skriva om koden. För att ge stöd för Win32- och WPF-grafikundersystem som används samtidigt i ett program tillhandahåller WPF en mekanism för att vara värd för objekt i ett Win32-fönster.

I den här handledningen beskrivs hur du skriver ett exempelprogram, Hit Test with Win32 Interoperation Sample, som värdar visuella objekt i WPF i ett Win32-fönster.

Krav

Den här handledningen förutsätter grundläggande kännedom om både WPF- och Win32-programmering. En grundläggande introduktion till WPF-programmering finns i Genomgång: Mitt första WPF-skrivbordsprogram. För en introduktion till Win32-programmering, se någon av de många böckerna om ämnet, särskilt Programming Windows av Charles Petzold.

Not

Den här handledningen innehåller ett antal kodexempel från den associerade exempelsamlingen. För läsbarhet innehåller den dock inte den fullständiga exempelkoden. Den fullständiga exempelkoden finns i Hit Test with Win32 Interoperation Sample.

Skapa värd-Win32-fönstret

Nyckeln till att vara värd för WPF-objekt i ett Win32-fönster är klassen HwndSource. Den här klassen omsluter WPF-objekten i ett Win32-fönster så att de kan införlivas i användargränssnittet (UI) som ett underordnat fönster.

I följande exempel visas koden för att skapa HwndSource-objektet som Win32-containerfönstret för de visuella objekten. Om du vill ange fönsterformat, position och andra parametrar för Win32-fönstret använder du objektet HwndSourceParameters.

// 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

Anteckning

Värdet för egenskapen ExtendedWindowStyle kan inte anges till WS_EX_TRANSPARENT. Det innebär att värd-Win32-fönstret inte kan vara transparent. Därför är bakgrundsfärgen för värd-Win32-fönstret inställd på samma bakgrundsfärg som det överordnade fönstret.

Lägga till visuella objekt i win32-värdfönstret

När du har skapat ett Win32-värdcontainerfönster för de visuella objekten kan du lägga till visuella objekt i det. Du vill se till att alla transformeringar av de visuella objekten, till exempel animeringar, inte sträcker sig utanför gränserna för värd-Win32-fönstrets avgränsningsrektangel.

I följande exempel visas koden för att skapa HwndSource-objektet och lägga till visuella objekt i det.

Notera

Egenskapen RootVisual för HwndSource-objektet är inställd på det första visuella objektet som läggs till i win32-värdfönstret. Det visuella rotobjektobjektet definierar den översta noden i det visuella objektträdet. Eventuella efterföljande visuella objekt som läggs till i win32-värdfönstret läggs till som underordnade objekt.

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

Implementera Win32-meddelandefiltret

Värd-Win32-fönstret för de visuella objekten kräver en filterprocedur för fönstermeddelande för att hantera meddelanden som skickas till fönstret från programkön. Fönsterproceduren tar emot meddelanden från Win32-systemet. Det kan vara indatameddelanden eller fönsterhanteringsmeddelanden. Du kan också hantera ett meddelande i fönsterproceduren eller skicka meddelandet till systemet för standardbearbetning.

Det HwndSource objekt som du definierade som överordnat för de visuella objekten måste referera till den fönstermeddelandefilterprocedur som du anger. När du skapar HwndSource-objektet anger du egenskapen HwndSourceHook så att den refererar till fönsterproceduren.

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

I följande exempel visas koden för att hantera meddelanden med vänster och höger musknapp. Koordinatvärdet för musträffspositionen finns i värdet för parametern lParam.

// 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

Bearbeta Win32-meddelanden

Koden i följande exempel visar hur ett träfftest utförs mot hierarkin för visuella objekt som finns i värd-Win32-fönstret. Du kan identifiera om en punkt ligger inom geometrin för ett visuellt objekt genom att använda metoden HitTest för att ange det visuella rotobjektet och koordinatvärdet som ska testas mot. I det här fallet är det visuella rotobjektet värdet för egenskapen RootVisual för det HwndSource objektet.

// 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

Mer information om träfftestning mot visuella objekt finns i Hit Testing in the Visual Layer.

Se även