Руководство по размещению визуальных объектов в приложении Win32

Windows Presentation Foundation (WPF) предоставляет широкие возможности для создания приложений. Однако при наличии существенных инвестиций в код Win32 может оказаться более эффективным, чтобы добавить функциональные возможности WPF в приложение, а не переписать код. Чтобы обеспечить поддержку подсистем графики Win32 и WPF, используемых одновременно в приложении, WPF предоставляет механизм размещения объектов в окне Win32.

В этом руководстве описывается, как написать пример приложения, хит-тест с помощью примера взаимодействия Win32, в котором размещаются визуальные объекты WPF в окне Win32.

Требования

В этом учебнике предполагается, что вы знакомы с основами программирования в WPF и Win32. Основные сведения о программировании WPF см. в пошаговом руководстве. Мое первое классическое приложение WPF. Общие сведения о программировании Win32 см. в любой из многочисленных книг по теме, в частности программирования Windows Чарльзом Петзольдом.

Примечание.

Этот учебник включает ряд примеров кода из связанного образца приложения. Однако для удобства чтения он не содержит полный пример кода. Полный пример кода см. в разделе Проверка нажатия с помощью примера взаимодействия Win32.

Создание окна размещения Win32

Ключом к размещению объектов WPF в окне Win32 является HwndSource класс. Этот класс упаковывает объекты WPF в окне Win32, что позволяет включить их в пользовательский интерфейс в качестве дочернего окна.

В следующем примере показан код для создания HwndSource объекта в качестве окна контейнера Win32 для визуальных объектов. Чтобы задать стиль окна, положение и другие параметры для окна Win32, используйте 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

Примечание.

Значение ExtendedWindowStyle свойства нельзя задать для WS_EX_TRANSPARENT. Это означает, что окно Win32 узла не может быть прозрачным. По этой причине цвет фона окна Win32 узла имеет тот же цвет фона, что и родительское окно.

Добавление визуальных объектов в окно размещения Win32

После создания окна контейнера Win32 узла для визуальных объектов можно добавить в него визуальные объекты. Необходимо убедиться, что любые преобразования визуальных объектов, например анимации, не выходят за рамки ограничивающего прямоугольника окна Win32 узла.

В следующем примере показан код для создания HwndSource объекта и добавления визуальных объектов в него.

Примечание.

Свойство RootVisualHwndSource объекта устанавливается на первый визуальный объект, добавленный в окно Узла Win32. Корневой визуальный объект определяет верхний узел дерева визуальных объектов. Все последующие визуальные объекты, добавленные в окно Узла Win32, добавляются в качестве дочерних объектов.

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

Реализация фильтра сообщений Win32

В окне Win32 узла для визуальных объектов требуется процедура фильтрации сообщений окна для обработки сообщений, отправляемых в окно из очереди приложения. Процедура окна получает сообщения из системы Win32. Это могут быть входные сообщения или сообщения управления окнами. Сообщение можно обработать в процедуре окна или передать системе для обработки по умолчанию.

Объект HwndSource , определенный как родительский объект для визуальных объектов, должен ссылаться на указанную процедуру фильтрации сообщений окна. При создании HwndSource объекта задайте HwndSourceHook для свойства ссылку на процедуру окна.

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

В следующем примере показан код для обработки сообщений при отпускании левой и правой кнопок мыши. Значение координат позиции попадания мыши содержится в значении 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

Обработка сообщений Win32

В следующем примере кода показано, как тест попадания выполняется в иерархии визуальных объектов, содержащихся в окне узла Win32. Вы можете определить, находится ли точка в геометрии визуального объекта, используя HitTest метод, чтобы указать корневой визуальный объект и значение координат для проверки попадания. В этом случае корневой визуальный объект является значением RootVisual свойства 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

Дополнительные сведения о проверке нажатия для визуальных объектов см. в разделе Проверка нажатия на визуальном уровне.

См. также