Windows Phone 7 开发探索笔记1——触控操作之Touch

    在Silverlight for Windows Phone中,我们有多种方法来获取设备触摸信息并对其进行控制。与此最密切相关的是以下几个事件Touch.FrameReported和定义在 UIElement中的 ManipulationStarted,ManipulationDelta 和 ManipulationCompleted。本节只讲解Touch.FrameReported事件。

一.Touch.FrameReported事件

    Touch.FrameReported事件提供了应用程序级的服务,是Silverlight for Windows Phone中提供的底层触控编程接口。我们可以通过它来获取操作系统或整个应用程序中每个触控点的信息。Touch是一个静态类,它只包含一个静态成员就是FrameReported事件。在程序中对此事件进行订阅时可以通过事件处理程序中的TouchFrameEventArgs参数获得我们想要的数据。

TouchFrameEventArgs类包含以下成员(图片来自MSDN):

 

    其中黄色的为TouchFrameEventArgs自身的成员。先来看GetTouchPoints方法,它会返回一个触控点的集合,当你的Windows Phone 7应用程序需要用多个手指来操作,同时你要清楚的知道每个手指所在的具体位置时它会非常有用。接下来是GetPrimaryTouchPoint方法,它返回的是主触控点(解惑主触摸点: 只有一个手指触摸屏幕时,这个触控点才叫做主(Primary)触控点。如果我们用一个手指触摸屏幕时,它一定是主触控点。在第一个手指仍触摸着屏幕时,将第二个手指放在屏幕上。很显然,第二个手指不是主触控点。但现在如果仍将第二个手指放在屏幕上,抬起第一个手指,然后再将其放回到屏幕上。它还是主触控点吗?不是!主触控点只会在没有其他手指触摸屏幕时才出现。)注意GetPrimaryTouchPoint和GetTouchPoints这两个方法都需要一个UIElement类型的参数,并且都返回与TouchPoint相关的信息。下面我们来看看TouchPoint类的属性:

 

TouchPoint是在屏幕上触摸的手指的一个抽象。它有4个只读属性:

Action类型为TouchAction枚举,包含3个值:Down,,Move和Up

Position类型为Point,它是相对于引用元素的左上角而言的,这里说的引用元素就是刚才提到的GetPrimaryTouchPoint和GetTouchPoints的UIElement参数,如果传入的参数是null,那么得到的Position就是相对于屏幕的左上角的(在传入非null值时,Position中的数据很有可能会是负的)。

Size类型是Size,它是要计算出屏幕中被触摸的一个矩形区域,不过这个属性好像并不能获取有效的值,在我的演示程序中它的Width和Height属性始终是1(也许是因为在模拟器上运行的原因)。

TouchDevice类型TouchDevice,它包含2个只读属性:一个用于区分不同手指的int型Id属性,以及一个UIElement类型的DirectlyOver属性,它是紧贴手指的最上层UI元素。注意:如果我们需要在多个手指之间进行区分,Id属性是至关重要的。在特定的手指触摸屏幕时,与该手指关联的一系列特定事件总是以Down操作开始,接着是 Move 事件,最后是 Up 事件。所有这些事件都将与相同的Id关联。(但大家不要认为主触控点的 Id 值总是0或1,虽然在我的演示程序中它始终是0。)

    现在让我们来整理一下思路:在订阅Touch.FrameReported后,通过调用事件处理程序中TouchFrameEventArgs类型参数的GetPrimaryTouchPoint和GetTouchPoints方法来获得相应的触控点数据。GetPrimaryTouchPoint返回的是TouchPoint,GetTouchPoints返回的是TouchPointCollection(此集合包含0个或多个TouchPoint)。从TouchPoint相应的属性中我们可以获取到更细致的数据,请看下面的代码:

代码
    public MainPage()
        {
            InitializeComponent();

            Touch.FrameReported += new TouchFrameEventHandler(Touch_FrameReported);
        }


        
void Touch_FrameReported(object sender, TouchFrameEventArgs e)
        {
            StringBuilder sb = new StringBuilder();

            
// 传入null表明获取到的触控点信息是以屏幕左上角为原点的。
            var primaryPoint = e.GetPrimaryTouchPoint(null);

            
if (primaryPoint != null)
            {
                
// 列出主触控点的位置。
                sb.Append("Position: X:" + primaryPoint.Position.X.ToString() + " Y:" + primaryPoint.Position.Y.ToString() + "\n");

                
// 列出主触控点的动作。
                sb.Append("Action: " + primaryPoint.Action.ToString() + "\n");

                
// 列出主触控点的设备。
                sb.Append("TouchDeviceId: " + primaryPoint.TouchDevice.Id.ToString() + "\n");

                
// 列出主触控点紧贴手指的UIElement元素。
                sb.Append("DirectlyOver: " + (primaryPoint.TouchDevice.DirectlyOver as FrameworkElement).Name + "\n");

                
// 列出主触控点的区域范围信息(这个属性并不能提供有用的值)。
                sb.Append("Size: Width:" + primaryPoint.Size.Width.ToString() + " Height:" + primaryPoint.Size.Height.ToString() + "\n");

                Debug.WriteLine(sb.ToString());
            }

            
// 传入null表明获取到的触控点信息是以屏幕左上角为原点的。
            var points = e.GetTouchPoints(null);

            
if (points != null)
            {
                
// 列出所有触控点的位置信息。
                foreach (var point in points)
                {
                    sb.Append("Position: X:" + point.Position.X.ToString() + " Y:" + point.Position.Y.ToString() + " " + point.Action.ToString() + "\n");
                }
            }

            txtblk.Text = sb.ToString();
        }

    在GetPrimaryTouchPoint返回的TouchPoint或GetTouchPoints方法返回的TouchPointCollection中的TouchPoint都包含3种动作信息,Down,Move和up,也就是说:当你按下然后抬起手指的时候分别会激发一次FrameReported事件,动作信息分别是Down和up,如果你的手指在屏幕上移动了,那么FrameReported就会被触发至少3次,动作信息为Down,Move,up(其中有可能移动了多次,而我们区分不出来,因为带Move信息的FrameReported事件可能会被触发多次)。参见下面的截图(图中的操作带Move信息的FrameReported事件被触发了2次):

 

下面的截图是上面的代码运行时模拟器的截图

clip_image008clip_image010clip_image012

另外,如果你用2个手指触摸屏幕,FrameReported会分别被触发,但此时如果你调用 GetPrimaryTouchPoint方法它只会返回第一个碰到屏幕的手指的触控信息。对于第二个手指GetPrimaryTouchPoint会返回null。多个手指与两个时情况相同。

二.SuspendMousePromotionUntilTouchUp方法和鼠标事件提升(Mouse-Event Promotion)

    有一个方法到现在还没有说到,它就是TouchFrameEventArgs类的SuspendMousePromotionUntilTouchUp方法。这个方法是用来禁止鼠标事件提升的。鼠标事件提升是源于桌面版的Silverlight,目的是使多点触控用户可以使用触控和笔势来代替鼠标移动或鼠标单击。比如,当用户使用多点触控设备点击一个按钮时,按钮的预期行为与鼠标被单击时的相同,所以桌面版Silverlight提供了将触控输入自动提升为鼠标事件的机制,它被延续到了Silverlight for Windows Phone中。但是鼠标事件提升只是针对主触控点(第一个触摸屏幕的手指同时没有其他手指触摸屏幕时),如果你不想让这个手指的动作被提升,就可以使用SuspendMousePromotionUntilTouchUp方法来挂起鼠标事件提升。

注意:SuspendMousePromotionUntilTouchUp方法只能在主触控点向下(Down)的动作时才能被调用,否则会抛出异常

当不满足上述条件调用时,程序抛出异常:

正确的调用方法:

代码
        void Touch_FrameReported(object sender, TouchFrameEventArgs e)
        {

            var primaryPoint = e.GetPrimaryTouchPoint(null);

            
if (primaryPoint != null && primaryPoint.Action == TouchAction.Down)
            {

                e.SuspendMousePromotionUntilTouchUp();

            }

            ………
        }

    不过在Windows Phone 7中,通常程序中不需要处理鼠标操作,除非在手机中包含有不能处理触控输入的控件。所以在大多数情况下我们无须禁止鼠标事件提升。

    好了,关于底层触控编程接口Touch类就介绍这么多内容,下一节我会介绍与UIElement类相关的高级触控编程接口。

 

 三.下载示例代码

WindowsPhoneTouchDemo.zip

 如果大家喜欢我的文章,请点击“推荐”,谢谢!

posted @ 2010-12-03 12:31  YinBa  阅读(3555)  评论(15编辑  收藏  举报