教學課程:在 Win32 應用程式中裝載視覺物件
更新:2007 年 11 月
Windows Presentation Foundation (WPF) 提供用來建立應用程式的豐富環境。不過,若您已對 Win32 程式碼投入相當的心力,更有效的方法是將 WPF 功能加入應用程式,而不是重新撰寫程式碼。為了提供在應用程式中同時 Win32 和 WPF 圖形子系統的支援,WPF 提供了一種將物件裝載在 Win32 視窗中的機制。
本教學課程說明如何撰寫下列範例應用程式:使用 Win32 互通性進行點擊測試範例;這個範例應用程式將 WPF 視覺物件裝載在 Win32 視窗中。
這個主題包含下列章節。
- 需求
- 建立裝載 Win32 視窗
- 將視覺物件加入至裝載 Host Win32 視窗
- 實作 Win32 訊息篩選
- 處理 Win32 訊息
- 相關主題
需求
本教學課程假設您已熟悉 WPF 和 Win32 程式設計的基本概念。如需 WPF 程式設計的基本簡介,請參閱 Windows Presentation Foundation 使用者入門。如需 Win32 程式設計的簡介,請參閱討論此主題的各種書籍,尤其是 Charles Petzold 所著的《Programming Windows》。
注意事項: |
---|
本教學課程包括摘錄自相關範例的許多程式碼範例。不過,為了方便閱讀,此課程並未包含完整的範例程式碼。如需完整的範例程式碼,請參閱使用 Win32 互通性進行點擊測試範例。 |
建立裝載 Win32 視窗
將 WPF 物件裝載在 Win32 視窗的關鍵是 HwndSource 類別。這個類別會將 WPF 物件包裝在 Win32 視窗中,讓您可以將這些物件當做子視窗加入使用者介面 (UI) 中。
下列範例顯示的程式碼可用來建立 HwndSource 物件,以做為視覺物件的 Win32 容器 (Container) 視窗。若要設定 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;
}
注意事項: |
---|
ExtendedWindowStyle 屬性的值不能設定為 WS_EX_TRANSPARENT。這表示裝載 Win32 視窗不能是透明的。因此,裝載 Win32 視窗的背景色彩會設定成與其父視窗相同的背景色彩。 |
將視覺物件加入至裝載 Host Win32 視窗
建立視覺物件的裝載 Win32 容器視窗之後,您就可以將視覺物件加入視窗中。您必須確定視覺物件的任何變化 (例如動畫) 都不會超過裝載 Win32 視窗週框 (Bounding Rectangle) 的範圍。
下列範例顯示的程式碼可用來建立 HwndSource 物件,並將視覺物件加入其中。
注意事項: |
---|
HwndSource 物件的 RootVisual 屬性設定為已加入至裝載 Win32 視窗的第一個視覺物件。這個根 (Root) 視覺物件定義了視覺物件樹狀結構的最上層節點。後續加入至裝載 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);
}
}
實作 Win32 訊息篩選
視覺物件的裝載 Win32 視窗需要使用視窗訊息篩選程序來處理從應用程式佇列 (Queue) 傳送到視窗的訊息。視窗程序會接收 Win32 系統傳來的訊息。這些訊息可能是輸入訊息或視窗管理訊息。您可以選擇在視窗程序中處理訊息,或是將訊息傳送給系統進行預設處理。
已定義為視覺物件父代 (Parent) 的 HwndSource 物件必須參考您所提供的視窗訊息篩選程序。當您建立 HwndSource 物件時,請設定 HwndSourceHook 屬性來參考該視窗程序。
parameters.HwndSourceHook = new HwndSourceHook(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;
}
處理 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();
}
}
如需對視覺物件進行點擊測試的詳細資訊,請參閱視覺分層中的點擊測試。