Samouczek: hosting obiektów Visual w aplikacji Win32

Program Windows Presentation Foundation (WPF) udostępnia bogate środowisko do tworzenia aplikacji. Jednak jeśli masz znaczną inwestycję w kod Win32, może być bardziej skuteczne dodanie funkcji WPF do aplikacji zamiast ponownego zapisywania kodu. Aby zapewnić obsługę podsystemów graficznych Win32 i WPF używanych współbieżnie w aplikacji, WPF zapewnia mechanizm hostowania obiektów w oknie Win32.

W tym samouczku opisano sposób pisania przykładowej aplikacji, Hit Test z przykładem Win32 Interoperation Sample, który hostuje obiekty wizualne WPF w oknie Win32.

Wymagania

W tym samouczku założono podstawową znajomość programowania zarówno WPF, jak i Win32. Aby zapoznać się z podstawowym wprowadzeniem do programowania WPF, zobacz Przewodnik: Moja pierwsza aplikacja klasyczna WPF. Aby zapoznać się z wprowadzeniem do programowania Win32, zobacz dowolną z licznych książek na ten temat, w szczególności programowania windows autorstwa Charlesa Petzolda.

Uwaga

Ten samouczek zawiera szereg przykładów kodu ze skojarzonego przykładu. Jednak w celu zapewnienia czytelności nie zawiera kompletnego przykładowego kodu. Pełny przykładowy kod można znaleźć w temacie Hit Test with Win32 Interoperation Sample (Test trafienia za pomocą przykładu współdziałania Win32).

Tworzenie okna Win32 hosta

Kluczem do hostowania obiektów WPF w oknie Win32 jest HwndSource klasa . Ta klasa opakowuje obiekty WPF w oknie Win32, umożliwiając ich włączenie do interfejsu użytkownika (UI) jako okna podrzędnego.

Poniższy przykład przedstawia kod tworzenia HwndSource obiektu jako okna kontenera Win32 dla obiektów wizualnych. Aby ustawić styl okna, położenie i inne parametry dla okna Win32, użyj HwndSourceParameters obiektu .

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

Uwaga

Nie można ustawić wartości ExtendedWindowStyle właściwości na WS_EX_TRANSPARENT. Oznacza to, że okno Win32 hosta nie może być przezroczyste. Z tego powodu kolor tła okna Win32 hosta jest ustawiony na ten sam kolor tła co okno nadrzędne.

Dodawanie obiektów wizualnych do okna Win32 hosta

Po utworzeniu okna kontenera Win32 hosta dla obiektów wizualnych można do niego dodać obiekty wizualne. Należy upewnić się, że wszystkie przekształcenia obiektów wizualizacji, takie jak animacje, nie wykraczają poza granice prostokąta ograniczenia okna Win32 hosta.

Poniższy przykład przedstawia kod tworzenia HwndSource obiektu i dodawania do niego obiektów wizualnych.

Uwaga

Właściwość RootVisualHwndSource obiektu jest ustawiona na pierwszy obiekt wizualny dodany do okna win32 hosta. Główny obiekt wizualizacji definiuje najbardziej górny węzeł drzewa obiektów wizualizacji. Wszystkie kolejne obiekty wizualne dodane do okna Win32 hosta są dodawane jako obiekty podrzędne.

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

Implementowanie filtru komunikatów Win32

Okno Win32 hosta dla obiektów wizualnych wymaga procedury filtrowania komunikatów okna do obsługi komunikatów wysyłanych do okna z kolejki aplikacji. Procedura okna odbiera komunikaty z systemu Win32. Mogą to być komunikaty wejściowe lub komunikaty zarządzania oknami. Opcjonalnie możesz obsłużyć komunikat w procedurze okna lub przekazać komunikat do systemu na potrzeby przetwarzania domyślnego.

Obiekt HwndSource zdefiniowany jako obiekt nadrzędny dla obiektów wizualnych musi odwoływać się do podanej procedury filtrowania komunikatów okna. Podczas tworzenia HwndSource obiektu ustaw HwndSourceHook właściwość , aby odwoływać się do procedury okna.

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

W poniższym przykładzie pokazano kod obsługi komunikatów po lewej i prawej stronie myszy. Wartość współrzędna pozycji trafienia myszy jest zawarta w wartości parametru 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

Przetwarzanie komunikatów Win32

Kod w poniższym przykładzie pokazuje, jak test trafienia jest wykonywany względem hierarchii obiektów wizualnych zawartych w oknie Win32 hosta. Możesz określić, czy punkt znajduje się w geometrii obiektu wizualizacji, używając HitTest metody w celu określenia głównego obiektu wizualnego i wartości współrzędnych do trafienia testowego. W takim przypadku główny obiekt wizualizacji jest wartością RootVisual właściwości HwndSource obiektu.

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

Aby uzyskać więcej informacji na temat testowania trafień względem obiektów wizualnych, zobacz Testowanie trafień w warstwie wizualnej.

Zobacz też