教程:在 Win32 应用程序中承载 Visual 对象
更新:2007 年 11 月
Windows Presentation Foundation (WPF) 提供用于创建应用程序的丰富环境。但是,如果您在 Win32 代码上有大量的投资,则将 WPF 功能添加到应用程序而不是重写代码的做法或许会更有效。为了为应用程序中并发使用的 Win32 和 WPF 图形子系统提供支持,WPF 提供了一种承载 Win32 窗口中的对象的机制。
本教程介绍了如何编写一个示例应用程序,使用 Win32 互操作进行命中测试的示例,该应用程序在 Win32 窗口中承载 WPF Visual 对象。
本主题包括下列各节。
- 要求
- 创建宿主 Win32 窗口
- 将 Visual 对象添加到宿主 Win32 窗口
- 实现 Win32 消息筛选器
- 处理 Win32 消息
- 相关主题
要求
本教程假定您基本熟悉 <token>TLA2#tla_winclient</token> 和 <token>TLA2#tla_win32</token> 编程。有关 WPF 编程的基本介绍,请参见 Windows Presentation Foundation 入门。有关对 Win32 编程的介绍,请参见众多关于此主题书籍中的任何一本,特别推荐由 Charles Petzold 编写的 Programming Windows(《Windows 编程》)。
说明: |
---|
本教程包含关联示例中的一些代码示例。但是,为了可读性起见,本教程并不包含完整的示例代码。有关完整的示例代码,请参见使用 Win32 互操作进行命中测试的示例。 |
创建宿主 Win32 窗口
在 Win32 窗口中承载 WPF 对象的关键是 HwndSource 类。此类在 Win32 窗口中包装 WPF 对象,允许将它们作为子级窗口合并到用户界面 (UI) 中。
下面的示例演示将 HwndSource 对象作为 Visual 对象的 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;
}
说明: |
---|
不能将 ExtendedWindowStyle 属性的值设置为 WS_EX_TRANSPARENT。这意味着宿主 Win32 窗口不能是透明的。因此,宿主 Win32 窗口的背景色将设置为与其父窗口相同的背景色。 |
将 Visual 对象添加到宿主 Win32 窗口
为 Visual 对象创建宿主 Win32 容器窗口后,可向其添加 Visual 对象。如果需要确保如动画等的 Visual 对象的任何转换,扩展时请勿超出宿主 Win32 窗口的边框。
下面的示例演示创建 HwndSource 对象并向其中添加 Visual 对象的代码。
说明: |
---|
将 HwndSource 对象的 RootVisual 属性设置为添加到宿主 Win32 窗口的第一个 Visual 对象。根 Visual 对象定义 Visual 对象树最顶层的节点。任何添加到宿主 Win32 窗口的后续 Visual 对象都作为子对象进行添加。 |
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 消息筛选器
Visual 对象的宿主 Win32 窗口需要窗口消息筛选器过程来处理从应用程序队列发送到该窗口的消息。窗口过程接收来自 Win32 系统的消息。这些消息可以为输入消息或窗口管理消息。可以选择在窗口过程中处理消息或将消息传递到系统进行默认处理。
定义为 Visual 对象的父级的 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 窗口中的 Visual 对象的层次结构执行命中测试。可以确定一个点是否处于 Visual 对象的几何图形之内,其方法是使用 HitTest 方法指定进行命中测试的根 Visual 对象和坐标值。在本例中,根 Visual 对象是 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();
}
}
有关对 Visual 对象进行命中测试的更多信息,请参见可视化层中的命中测试。