添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
上篇我们介绍了WPF和WinForm的开发特性和混搭(请戳蓝色字体 [精华分享] 当WPF混搭上WinForm,这个C#不一般(上) ),下面让我们继续介绍二者混搭时的一些经验分享。 <混搭注意事 项> 1. 空域问题
为在同一个窗口中集成WPF和WinForm窗体内容,需要能隔离出窗口的一部分,用于“外来的”内容。 例如,将3D图形放到WinForm窗体应用程序中是完全合理的,因为可在窗口的不同区域放置3D图形(甚至使3D图形占满整个窗口)。但是在WinForm窗体程序中使用WPF元素为所有按钮制作新的外观,这是不容易实现的,也是不值得的,因为需要为每个按钮创建单独的WPF区域。
除了考虑复杂程度外,还有一些问题是不可能通过WPF互操作功能解决的。 例如,不能通过重叠来组合WPF和WinForm窗体内容。这意味着不能使用WPF动画发送元素,使其飞过由WinForm窗体渲染的区域。同样,不能通过在WPF区域中重叠部分透明的WinForm窗体内容来将它们混合在一起。 这两种情况都违反了空域规则,该规则指示WPF和WinForm窗体必须总是使用它们自己的不同窗口区域,即它们专门管理的区域。 下图 显示了哪些情况是允许的,以及哪些情况是不允许的。
从技术角度看,空域规则是由于在包含WPF内容和WinForm窗体内容的窗口中, 两个区域具有不同的窗口句柄hwnd 这一原因造成的,每个句柄单独地加以管理、渲染和刷新。 窗口句柄通过Windows操作系统进行管理 。在经典的Windows应用程序中,每个控件都是独立窗口,这意味着每个控件真正拥有不同部分的屏幕区域。显然,这种类型的“窗口”和浮动在屏幕上的顶级窗口是不同的——只是独立区域(矩形或其他形状)。 在WPF中,窗口模型是完全不同的——只有单独的顶级窗口句柄,并且WPF引擎组织整个窗口,使窗口能够更好地进行渲染(如动态反锯齿效果),并且具有更大的灵活性(例如,在边界之外渲染内容的可视化对象)。
空域规则的实现非常简单,如果在WPF内容之上放置WinForm窗体内容,不管是在标记中的什么地方声明的,也不管使用的是什么布局容器,你会发现WinForm窗体内容总在上面。这是因为WPF内容是单独窗日,并且包含WinForm窗体内容的容器被实现为独立的窗口,该窗口总是显示在WPF窗口中某一部分的上面。
如果在WinForm窗体之上放置WPF内容,结果就不同了。WinForm窗体中的每个控件都是单独窗口,所以它们拥有自己的句柄。因此,WPF内容可以根据z索引,相对于同一窗口中其他WinForm窗体控件层叠在任何位置(z索引是向父控件的Controls集合中添加控件的顺序决定的,所以后添加的控件会显示在那些先添加的控件的上面)。 然而,WPF内容仍有自己完全独立的区域,WPF内容存在于独立区域中,这意味着不能使用透明或其他任何技术部分改写WinForm窗体内容(或与其他元素组合到一起)。 2. 按键问题
WPF和WinForm窗体之问的互操作之所以能够工作,是因为两种类型的内容可以严格地分离。每个区域处理自己的渲染和刷新,并独立地与鼠标进行交互。然而, 隔离并不总是完美的 例如,对于键盘处理这会造成潜在的问题,有时需要全局访问整个窗体。 下面是一些例子:
当使用Tab键从一个区域的最后一个控件移走焦点时,期望将焦点移到下一个区域的第一个控件。
当使用快捷键触发控件(如按钮)时,期望按钮进行响应,而不管按钮位于窗口中的哪个区域。
当使用标签的助记码时,期望焦点移到链接的控件上。
类似地,如果使用预览事件挂起击键,那么不管当前是哪个控件具有焦点,都不希望引发任何区域中相应的击键事件。
上面所有这些期望的行为都可以实现,而不需要进行任何的操作。键盘支持并不总是那么完美,而且可能遇到一些与键盘相关的问题。 下面列出了一些需要注意的问题:
尽管WPF支持击键转发系统,以确保所有元素和控件都能够获得处理键盘输入的机会,但WPF的键盘处理模型和WinForm窗体仍是不同的。所以,当焦点位于WinForm窗体内容的内部时,不会从WindowsFormsHost控件接收到键盘事件。 同样,如果用户从一个控件移到WindowsFormsHost控件内的另一个控件时,不能从WindowsFormsHost控件接收到GotFocus和LostFocus事件。当在WindowsFormsHost控件内移动鼠标时不会为WindowsFormsHost控件引发MouseMove事件。
当焦点从WindowsFormsHost内部的控件移到WindowsFormsHost外部的元素上时,不会引发WinForm窗体验证。而只有当焦点在WindowsFormsHost内部从一个控件移到另一个控件时才会引发WinForm窗体验证(WPF内容和WinForm窗体内容在本质上是相互独立的窗口,这是合理的,因为上面的行为正是当不同的应用程序之间进行切换时得到的体验)。
如果当焦点在WindowsFormsHost控件内部的某个位置时最小化窗口,那么当还原窗口时焦点可能不会还原到原来的位置。 3. 属性映射
在WPF和WinForm窗体之间的互操作中, 最笨拙的一个细节是它们使用的属性类似但又不同。 例如,WPF控件有Background属性,可通过该属性提供用于绘制背景的画刷。WinForm窗体控件使用更简单的BackColor属性,该属性使用颜色(基于ARGB值)填充背景。尽管它们经常用于设置控件外观,但这两个属性之间没有任何关联。
在大多数情况下问题不大,可根据使用的对象,强制开发人员简单地在两套 API之间进行切换。WPF还通过属性转换器的特性提供了一些额外的支持。
属性转换器不允许编写WPF风格的标记,而且只能用于WinForm窗体控件。实际上, 属性转换器非常简单。它们简单地将WindowsFormsHost (或ElementHost)控件的几个基本属性从一个系统转换到另一个系统,从而可将这些属性应用于子控件。
例如,如果设置WindowsFormsHost.IsEnable属性,就会相应地修改内部控件的Enabled属性。这个特性不是必需的(可通过直接修改子元素的Enabled属性,而不是容器的Enabled属性,得到相同的效果),但这一特性可以使代码更加清晰。
为使这一特性奏效,WindowsFormsHost类和ElementHost类都提供了PropertyMap属性集合,该集合负责将属性名和标识执行转换方法的委托关联起来。通过使用某个方法,属性映射系统能够处理关联转换,例如从BackColor属性到Background属性,以及反过来从Background属性到BackColor属性。在默认情况下,每个PropertyMap属性集合由默认的关联设置填充(可随意创建自己的关联设置或替换己有的关联设置,这种低级方法意义不大)。
下表列出了 由WindowsFormsHost和ElementHost类提供的标准属性映射转换:
<WPF与WinForm混搭问题总结> 虽然WPF与WinForm技术都是构建在.NET托管代码基础上的,可以使用微软提供的互操作类完成混搭功能,但是在使用WPF与WinForm混搭技术的过程中会有如下问题:
WPF渲染机制和Winform不一样, WPF版插件样式可能会发生变化,比如字体样式等。
WinForm主程序中没有WPF程序中的app.xaml, 不能直接嵌入使用全局WPF样式文件,只能在WPF插件的工程中嵌入样式文件
WPF的按键处理模型和WinForm的按键处理模型不一样, 按键处理会有很多问题。
WinForm和WPF控件 空域问题 ,前面已经详细概述。
在WinForm框架中打开WPF插件速度和操作界面反应速度会变慢,因为用WindowsFormsHost托管WPF插件,相当于在.NET之上又托管了一层WindowsFormsHost,所以有一定的 性能损失。 本文首先介绍WinForm与WPF技术的发展历史和介绍WPF技术与WinForm相比的优越特性,重点剖析WPF与WinForm之间的窗体混搭和控件混搭,虽然WPF与WinForm能实现混搭,但由于两者的渲染机制完全不同,所以或多或少会出现一些问题,WPF基于DirectX的渲染机制加上现代化的界面开发思想,使得WPF成为开发Windows客户端程序的首选技术,因此不建议使用陈旧的WinForm技术开发Windows客户端应用程序,强烈建议使用新式的WPF技术开发Windows客户端应用。
如需转载请联系 0571- 28829811 WPF C# WinForm