共用方式為


教學課程:在 Win32 應用程式中裝載視覺物件

Windows Presentation Foundation (WPF) 提供一個用來建立應用程式的豐富環境。 不過,如果您已長期開發 Win32 程式碼,將 WPF 功能新增至應用程式,可能會比重寫原始程式碼更有效率。 為針對應用程式中同時使用的 Win32 和 WPF 圖形子系統提供支援,WPF 提供在 Win32 視窗中裝載物件的機制。

本教學課程說明如何撰寫可在 Win32 視窗中裝載 WPF 視覺物件的範例應用程式:使用 Win32 交互操作進行點擊測試範例 (英文)。

需求

本教學課程假設您對 WPF 和 Win32 程式設計已有基本的熟悉度。 如需 WPF 程式設計的基本介紹,請參閱逐步解說:我的第一個 WPF 傳統型應用程式 (英文)。 如需 Win32 程式設計的簡介,請參閱有關該主旨的任何書籍,特別參考《Programming Windows》(Windows 程式設計) (英文),作者:Charles Petzold。

注意

本教學課程包含一些來自相關範例的程式碼範例。 不過,為了方便閱讀,並未包含完整的範例程式碼。 如需完整的範例程式碼,請參閱使用 Win32 交互操作進行點擊測試範例 (英文)

建立 Win32 主機視窗

在 Win32 視窗中裝載 WPF 物件的索引鍵是 HwndSource 類別。 這個類別會包裝 Win32 視窗中的 WPF 內容,以將 WPF 內容併入使用者介面中做為子視窗。

下列範例顯示用來將 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 物件並在其中新增視覺物件的程式碼。

注意

HwndSource 物件的 RootVisual 屬性會設定為新增至主機 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 方法來指定根視覺物件以及要執行點擊測試的座標值,識別某個點是否位於視覺物件的幾何內。 在此情況下,根視覺物件是 HwndSource 物件的 RootVisual 屬性值。

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

如需有關視覺物件點擊測試的詳細資訊,請參閱視覺分層中的點擊測試

另請參閱