Sdílet prostřednictvím


Kurz: Hostování vizuálních objektů v aplikaci Win32

Windows Presentation Foundation (WPF) poskytuje bohaté prostředí pro vytváření aplikací. Pokud ale máte značné investice do kódu Win32, může být efektivnější přidat funkce WPF do vaší aplikace místo přepsání kódu. Pro zajištění podpory grafických subsystémů Win32 a WPF používaných souběžně v aplikaci poskytuje WPF mechanismus pro hostování objektů v okně Win32.

Tento tutoriál popisuje, jak napsat ukázkovou aplikaci, Hit Test s ukázkou pro interakci s Win32, která hostuje vizuální objekty WPF v okně Win32.

Požadavky

V tomto kurzu se předpokládá základní znalost programování WPF i Win32. Základní úvod do programování WPF naleznete v tématu Návod: Moje první desktopová aplikace WPF. Úvod do programování Win32, viz některé z mnoha knih na téma, zejména Programování Windows Charles Petzold.

Poznámka

Tento kurz obsahuje řadu příkladů kódu z přidružené ukázky. Pro čitelnost ale neobsahuje úplný vzorový kód. Pro úplný vzorový kód se podívejte na Hit Test s ukázkou spolupráce Win32.

Vytvoření okna Win32 hostitele

Klíčem k hostování objektů WPF v okně Win32 je třída HwndSource. Tato třída zabalí objekty WPF v okně Win32, což umožňuje jejich začlenění do uživatelského rozhraní (UI) jako podřízeného okna.

Následující příklad ukazuje kód pro vytvoření objektu HwndSource jako okno kontejneru Win32 pro objekty vizuálu. Chcete-li nastavit styl okna, umístění a další parametry pro okno Win32, použijte objekt 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

Poznámka

Hodnotu vlastnosti ExtendedWindowStyle nelze nastavit na WS_EX_TRANSPARENT. To znamená, že okno Win32 hostitele nemůže být transparentní. Z tohoto důvodu je barva pozadí okna hostitele Win32 nastavená na stejnou barvu pozadí jako nadřazené okno.

Přidání vizuálních objektů do okna Host Win32

Jakmile vytvoříte okno kontejneru Win32 hostitele pro objekty vizuálu, můžete do něj přidat vizuální objekty. Budete chtít zajistit, aby všechny transformace vizuálních objektů, jako jsou animace, nepřesahují hranice ohraničujícího obdélníku okna Win32 hostitele.

Následující příklad ukazuje kód pro vytvoření HwndSource objektu a přidání vizuálních objektů do něj.

Poznámka

Vlastnost RootVisual objektu HwndSource je nastavena na první objekt vizuálu přidaný do okna Win32 hostitele. Kořenový objekt vizuálního objektu definuje nejvyšší uzel stromu vizuálních objektů. Všechny další vizuální objekty přidané do okna Win32 hostitele se přidají jako podřízené objekty.

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

Implementace filtru zpráv Win32

Hostitelské okno Win32 pro vizuální objekty vyžaduje postup filtru zpráv okna pro zpracování zpráv odesílaných do okna z aplikační fronty. Procedura okna přijímá zprávy ze systému Win32. Může se jednat o vstupní zprávy nebo zprávy správy oken. Volitelně můžete zpracovat zprávu v postupu okna nebo předat zprávu systému pro výchozí zpracování.

Objekt HwndSource, který jste definovali jako nadřazený objekt pro objekty vizuálu, musí odkazovat na proceduru filtru zpráv okna, kterou zadáte. Při vytváření objektu HwndSource nastavte vlastnost HwndSourceHook tak, aby odkazovala na proceduru okna.

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

Následující příklad ukazuje kód pro zpracování zpráv po uvolnění levého a pravého tlačítka myši. Hodnota souřadnic pozice myši je obsažena v hodnotě 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

Zpracování zpráv Win32

Kód v následujícím příkladu ukazuje, jak se test přístupnosti provádí proti hierarchii vizuálních objektů obsažených v okně Win32. Pomocí metody HitTest můžete určit, zda je bod v geometrii vizuálního objektu, a to tak, že určíte kořenový vizuální objekt a hodnotu souřadnice, proti které se má provést test. V tomto případě je kořenový vizuální objekt hodnotou vlastnosti RootVisual objektu HwndSource.

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

Další informace o testování s využitím vizuálních objektů naleznete v tématu Hit Testing ve vizuální vrstvě.

Viz také