更新:2007 年 11 月
本主题列出了在创作同时使用 WPF 和 Windows 窗体技术的混合应用程序时可能发生的一些常见问题。
重叠控件
控件可能不按预期的方式重叠。Windows 窗体为每个控件使用一个单独的 HWND。WPF 为一个页面上的所有内容使用一个 HWND。这一实现差异导致意外的重叠行为。
WPF 中承载的 Windows 窗体控件总是出现在 WPF 内容之上。
ElementHost 控件中承载的 WPF 内容出现在 ElementHost 控件的 Z 顺序中。可以重叠 ElementHost 控件,但所承载的 WPF 内容不能结合或交互。
子属性
WindowsFormsHost 和 ElementHost 类只能承载单个子控件或元素。若要承载多个控件或元素,必须使用容器作为子内容。例如,可以向 System.Windows.Forms.Panel 控件添加 Windows 窗体按钮和复选框控件,然后将该面板分配给 WindowsFormsHost 控件的 Child 属性。但是,不能将按钮和复选框控件分别添加到同一 WindowsFormsHost 控件。
缩放
WPF 和 Windows 窗体具有不同的缩放模型。一些 WPF 缩放变换对于 Windows 窗体控件是有意义的,但其他变换是无意义的。例如,将 Windows 窗体 控件缩放到 0 是可行的,但如果您尝试将同一控件重新缩放回非零值,则该控件的大小仍然为 0。有关更多信息,请参见 WindowsFormsHost 元素的布局注意事项。
适配器
在使用 WindowsFormsHost 和 ElementHost 类时可能会发生混乱,因为它们包含一个隐藏容器。WindowsFormsHost 和 ElementHost 类都具有一个名为“适配器”的隐藏容器,它用来承载内容。对于 WindowsFormsHost 元素,该适配器派生自 System.Windows.Forms.ContainerControl 类。对于 ElementHost 控件,该适配器派生自 DockPanel 元素。如果您发现其他互操作主题中提到了适配器,那么所讨论的就是这个容器。
嵌套
不支持在 ElementHost 控件内部嵌套 WindowsFormsHost 元素。也不支持在 WindowsFormsHost 元素内部嵌套 ElementHost 控件。
焦点
焦点在 WPF 和 Windows 窗体中的工作方式是不同的,这意味着在混合应用程序中可能发生焦点问题。例如,如果 WindowsFormsHost 元素内部具有焦点,那么,当最小化并还原页面,或者显示模式对话框时,WindowsFormsHost 元素内部的焦点可能会丢失。WindowsFormsHost 元素仍然具有焦点,但该元素内部的控件可能不具有焦点。
数据验证也受到焦点的影响。验证在 WindowsFormsHost 元素中有效,但当您按 Tab 键离开 WindowsFormsHost 元素或者在两个不同的 WindowsFormsHost 元素之间切换时,验证将无效。
属性映射
某些属性映射需要先进行大量的转译,才能将 WPF 和 Windows 窗体技术之间不同的实现桥接起来。通过属性映射,可以使您的编码对字体、颜色和其他属性方面的更改做出反应。通常,属性映射的工作方式是侦听属性Changed 事件或 On属性Changed 调用,然后在子控件或其适配器上设置适当的属性。有关更多信息,请参见Windows 窗体和 WPF 属性映射。
所承载内容上的布局相关属性
在分配 WindowsFormsHost.Child 或 ElementHost.Child 属性后,将自动设置所承载内容上的几个布局相关属性。更改这些内容属性会导致意外的布局行为。
将停靠所承载的内容,以便填充 WindowsFormsHost 和 ElementHost 父级。为了启用此填充行为,在设置子属性时,将设置多个属性。下表列出了由 ElementHost 和 WindowsFormsHost 类设置的内容属性。
宿主类 |
内容属性 |
---|---|
不要在所承载的内容上直接设置这些属性。有关更多信息,请参见WindowsFormsHost 元素的布局注意事项。
导航应用程序
导航应用程序不能维护用户状态。在导航应用程序中使用 WindowsFormsHost 元素时,该元素将重新创建其控件。当用户通过导航操作离开承载 WindowsFormsHost 元素的页面,然后又返回到该页面时,将发生重新创建子控件的操作。用户已经键入的任何内容都将丢失。
消息循环互操作
在使用 Windows 窗体消息循环时,可能无法按照预期方式处理消息。EnableWindowsFormsInterop 方法由 WindowsFormsHost 构造函数调用。此方法向 WPF 消息循环中添加一个消息筛选器。如果 System.Windows.Forms.Control 是消息的目标,此筛选器会调用 Control.PreProcessMessage 方法并且转换/调度该消息。
如果您在 Windows 窗体消息循环中使用 Application.Run 显示了一个 Window,那么除非调用 EnableModelessKeyboardInterop 方法,否则不能键入任何内容。EnableModelessKeyboardInterop 方法接受一个 Window,并且添加一个 System.Windows.Forms.IMessageFilter,后者将与键相关的消息重新传送到 WPF 消息循环。有关更多信息,请参见Windows 窗体和 WPF 互操作性输入结构。
不透明度和分层
HwndHost 类不支持分层。这意味着在 WindowsFormsHost 元素上设置 Opacity 属性不起作用,并且不会与 AllowsTransparency 设置为 true 的其他 WPF 窗口不会产生混合效果。
释放
如果未正确释放类,则会泄漏资源。在混合应用程序中,请确保释放 WindowsFormsHost 和 ElementHost 类,否则会泄漏资源。Windows 窗体在 ElementHost 控件的非模式 Form 父级关闭时释放该控件。WPF 在应用程序关闭时释放 WindowsFormsHost 元素。可以在 Windows 窗体消息循环的 Window 中显示 WindowsFormsHost 元素。在这种情况下,代码将无法收到有关正在关闭应用程序的通知。
启用视觉样式
Windows 窗体控件上的 Microsoft Windows XP 视觉样式可能未启用。Application.EnableVisualStyles 方法在 Windows 窗体应用程序的模板中调用。尽管默认情况下不会调用此方法,但如果您使用 Visual Studio 来创建项目,则会获得控件的 Microsoft Windows XP 视觉样式(如果 Comctl32.dll 的 6.0 版可用)。在线程上创建句柄之前,必须调用 EnableVisualStyles 方法。有关更多信息,请参见如何:在混合应用程序中启用视觉样式。
授权控件
授权的 Windows 窗体控件会在消息框中向用户显示许可信息,对于混合应用程序,这可能会导致意外行为。某些授权控件会显示一个对话框来响应创建句柄的操作。例如,授权控件可能会通知用户需要许可证,或者用户还可以试用该控件三次。
WindowsFormsHost 元素派生自 HwndHost 类,而子控件的句柄是在 BuildWindowCore 方法内部创建的。HwndHost 类不允许在 BuildWindowCore 方法中处理消息,但显示对话框会导致发送消息。若要启用此许可方案,请在将该控件分配为 WindowsFormsHost 元素的子级之前,在该控件上调用 Control.CreateControl 方法。
WPF 设计器
通过使用 Visual Studio Windows Presentation Foundation (WPF) 设计器可以设计您的 WPF 内容。以下各节将列出在使用 WPF 设计器创作混合应用程序时可能发生的一些常见问题。
在设计时忽略 BackColorTransparent
BackColorTransparent 属性可能不会起到设计时所预期的作用。
如果 WPF 控件不在可见的父级上,则 WPF 运行时将忽略 BackColorTransparent 值。忽略 BackColorTransparent 可能是因为在单独的 AppDomain 中创建了 ElementHost 对象。但是,运行应用程序时,BackColorTransparent 不会起到预期的作用。
删除 obj 文件夹时将出现设计时错误列表
如果删除 obj 文件夹,则将出现设计时错误列表。
使用 ElementHost 进行设计时,Windows 窗体设计器将使用对象的 obj 文件夹内 Debug 或 Release 文件夹中所生成的文件。如果删除这些文件,则将出现设计时错误列表。若要解决此问题,请重新生成项目。有关更多信息,请参见Windows 窗体设计器中的设计时错误。
ElementHost 和 IME
在 ElementHost 中承载的 WPF 控件当前不支持 ImeMode 属性。所承载的控件将忽略对 ImeMode 的更改。