解决在Windows Phone中的WebBrowser控件中的zoom和ScrollViewer的滑动冲突
这篇博文主要是描述了一个解决在Windows Phone中的WebBrowser控件中的zoom和ScrollViewer滑动冲突的helper类。
Windows Phone 7应用的开发者可以通过使用Webbrowser控件使用在IE9中的拥有的所有功能。该空间允许开发者在程序中呈现本地或者远程的HTML和JavaScript内容。你会发现这个控件比较多的应用与RSS阅读器,这些网页内容可以在程序中良好的呈现而不用再去启动IE浏览器(PS:在Windows Phone中启动IE是要利用启动器的)。WebBrowser也可以用于基于HTML5的应用程序,例如: Property Finder, the PhoneGap-based application I developed recently。
现在我们在使用WebBrowser时,常常碰到的一个问题是:怎么样去处理好manipulation事件。
举个例子,在开发过程中遇到了这样一种情况:在Pivot控件里放了一个WebBrowser控件,怎么样去判断和处理横向的滑动手势是要根据Pivot做切换还是用根据WebBrowser做页面内容的移动呢?
在HTML5应用程序中,你可以通过对元数据viewport的设置来对浏览器的评议和缩放做一些控制,例如以下代码就是禁止浏览器的滑动行为:
<meta name="viewport" content="user-scalable=no" />
通过添加上面的meta-tag到HTML页面虽然可以禁止用户使用Pinch手势时页面进行缩放,当时不管怎么说都是一个很完美的解决方法。因为用户还是能缩放页面,只不过是当他们释放手指时,又还原到原来的尺寸罢了。
解决方法
我最初以为暂时应该是没有办法去控制WebBrowser控件的行为,它毕竟是围绕着本地控制被.Net包裹着。但是我偶让发现quetzalcoatl 在StackOverflow上的一些回答,quetzalcotl对WebBrowser包裹的.Net层进行了深入的挖掘,发现了一个有趣的控件---PanZoomContainer。
如果你检查过WebBrowser的可视化树,你会发现下面的结构:
\-WebBrowser
\-Border
\-Border
\-PanZoomContainer
\-Grid
\-Border (*)
\-ContentPresenter
\-TileHost
(可视化转换同样是用了Colin Eberhardt写的一个非常有用的工具-Linq to VisualTree )
这棵可视化树的结构很简单,由一些Grid和Border组成。此中最重要的要属TileHost,他是本地IE9的组件(当然PanZoomContainer也是)。实际上TileHost比不处理手势触发的事件,而是由PanZoomContainer处理的。PanZoomContainer把这些事件转换成手势(如:缩放),并把结果返回给TileHost。
这就意味着我们可以阻止manipulation事件继续传递到PanZoomContainer,并在它们转换为手势前取消它们。
这个Utility类主要是处理这些事件链接到Border上。由于这些事件就被取消了,当事件接收各种的判断条件时通过这些条件可以判断出平移和滑动。
这个类的源码贴在这里:
using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using LinqToVisualTree; using Microsoft.Phone.Controls; /// <summary> /// Suppresses pinch zoom and optionally scrolling of the WebBrowser control /// </summary> public class WebBrowserHelper { private WebBrowser _browser; /// <summary> /// Gets or sets whether to suppress the scrolling of /// the WebBrowser control; /// </summary> public bool ScrollDisabled { get; set; } public WebBrowserHelper(WebBrowser browser) { _browser = browser; browser.Loaded += new RoutedEventHandler(browser_Loaded); } private void browser_Loaded(object sender, RoutedEventArgs e) { var border = _browser.Descendants<Border>().Last() as Border; border.ManipulationDelta += Border_ManipulationDelta; border.ManipulationCompleted += Border_ManipulationCompleted; } private void Border_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e) { // suppress zoom if (e.FinalVelocities.ExpansionVelocity.X != 0.0 || e.FinalVelocities.ExpansionVelocity.Y != 0.0) e.Handled = true; } private void Border_ManipulationDelta(object sender, ManipulationDeltaEventArgs e) { // suppress zoom if (e.DeltaManipulation.Scale.X != 0.0 || e.DeltaManipulation.Scale.Y != 0.0) e.Handled = true; // optionally suppress scrolling if (ScrollDisabled) { if (e.DeltaManipulation.Translation.X != 0.0 || e.DeltaManipulation.Translation.Y != 0.0) e.Handled = true; } } }
在属性范围内查找,在我的HTML5应用程序中,当用户从一个页面跳转到下一个页面时,JavaScript代码可以设置通过设置上述helper类的ScrollDisabled属性,从而通知Silverlight容器是否当前界面启用了滑动。
我希望这个简单的Utility类对大家能有帮助,只需要复制这段代码到你的应用程序中就行了。Note,这里使用到了Linq to VisualTree浏览WebBrowser的可视化树,因此你也需要到这里去了解Linq to VisualTree的相关信息。
原文作者:November 17th, 2011 by Colin Eberhardt
原文地址:Suppressing Zoom and Scroll interactions in the Windows Phone 7 WebBrowser Control