主要内容:

1.指针事件

2.操作事件

1.指针事件

指针事件由各种活动输入源引发,包括触摸、触摸板、笔和鼠标(它们替代传统的鼠标事件)。指针事件基于单一输入点(手指、笔尖、鼠标光标),但不支持基于速度的交互。下面是指针事件列表及其相关的事件参数列表:

事件或类 描述
PointerPressed 单根手指触摸屏幕时发生。
PointerReleased 该同一触摸接触抬起时发生。
PointerMoved 在屏幕上拖动指针时发生。
PointerEntered 在指针进入元素的点击测试区时发生。
PointerExited 在指针退出元素的点击测试区时发生。
PointerCanceled 异常丢失触摸接触时发生。
PointerCaptureLost 当另一个元素捕获指针时发生。
PointerWheelChanged 当鼠标滚轮的增量值更改时发生。
PointerRoutedEventArgs 为所有指针事件提供数据。

这些事件都是基于UI共同基类UIElement类的事件,对于大多数的UI元素都是适用的,利用上表中的前5个事件就基本可以实现单指操作的各种场景。一般用得最多的是PointerEntered和PointerExited两个事件。使用时,我们既可以在XAML里面注册这些事件,也可以在构造函数里面进行注册。

           

然后我们在这些事件里通过Debug.WriteLine("触发PointerXXX事件");打印出如下调试信息:

可以发现依次触发的事件是PointerEntered、PointerPressed、PointerMoved、PointerReleased、PointerExisted,手指只要在屏幕上稍微滑动一下,就有很多很多的PointerMoved事件被触发。。。

我们来看实例:

通过在圆上滑动来控制方块在一个区域的移动。

XAML:在这里使用的布局容器是Canvas,便于后面方块位置的控制。

  1. <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,24,0,28">
  2. <TextBlock x:Name="ApplicationTitle" Text="鼠标事件" FontSize="20"/>
  3. <Ellipse Height="100" Width="100" Fill="Red" Name="ellipse1" />
  4. </StackPanel>
  5. <Canvas x:Name="canvas" Background="DimGray" Height="400" Width="320" Grid.Row="1">
  6. <Rectangle x:Name="rect" Fill="BurlyWood" Canvas.Left="140" Canvas.Top="180" Height="40" Width="40"></Rectangle>
  7. </Canvas>

C#代码:判断是点击操作还是滑动操作,以及左滑右滑等是固定模式的代码,能理解就理解,不用刻意琢磨。还需注意如何获取控件在Canvas里的位置以及把方块限定在一个区域内。

  1. private void ellipse1_PointerExited(object sender, PointerRoutedEventArgs e)
  2. {
  3. Debug.WriteLine("触发PointerExited事件");
  4. Point end = e.GetCurrentPoint(ellipse1).Position;
  5. double angle = ;
  6. double verticalDistance = (double)rect.GetValue(Canvas.TopProperty);
  7. double horizontalDistance = (double)rect.GetValue(Canvas.LeftProperty);
  8.  
  9. if (Math.Abs(end.X - start.X) < && Math.Abs(end.Y - start.Y) < )
  10. {
  11. angle = ;
  12. }
  13. else if (end.X > start.X)
  14. {
  15. if (end.Y > start.Y)
  16. {
  17. angle = - Math.Atan((end.Y - start.Y) * 1.0 / (end.X - start.X)) * / Math.PI;
  18. }
  19. else
  20. {
  21. angle = Math.Atan((start.Y - end.Y) * 1.0 / (end.X - start.X)) * / Math.PI;
  22. }
  23. }
  24. else if (end.X < start.X)
  25. {
  26. if (end.Y > start.Y)
  27. {
  28. angle = Math.Atan((end.Y - start.Y) * 1.0 / (start.X - end.X)) * / Math.PI + ;
  29. }
  30. else
  31. {
  32. angle = - Math.Atan((start.Y - end.Y) * 1.0 / (start.X - end.X)) * / Math.PI;
  33. }
  34. }
  35. if (angle == )
  36. {
  37. //点击操作
  38. }
  39. else if (angle >= && angle < )
  40. {
  41. // 滑动操作:从下往上
  42. if (verticalDistance >)
  43. Canvas.SetTop(rect, (double)rect.GetValue(Canvas.TopProperty)-);
  44. }
  45. else if (angle <= || angle > )
  46. {
  47. // 滑动操作:从左向右滑
  48. if (horizontalDistance < canvas.Width-)
  49. Canvas.SetLeft(rect, (double)rect.GetValue(Canvas.LeftProperty) + );
  50. }
  51. else if (angle >= && angle < )
  52. {
  53. //滑动操作:从右向左滑
  54. if (horizontalDistance >)
  55. Canvas.SetLeft(rect, (double)rect.GetValue(Canvas.LeftProperty) - );
  56. }
  57. else if (angle >= && angle < )
  58. {
  59. //滑动操作:从上往下
  60. if (verticalDistance <canvas.Height-)
  61. Canvas.SetTop(rect, (double)rect.GetValue(Canvas.TopProperty) + );
  62. }
  63. }
  64. private void ellipse1_PointerEntered(object sender, PointerRoutedEventArgs e)
  65. {
  66. start = e.GetCurrentPoint(ellipse1).Position;
  67. }

来一个很小的预览图意思一下:

简单的实现一个涂鸦板

XAML:定义了一个Canvas、三个AppBarButton。

  1. <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
  2. <Canvas Name="canvas"
  3. Background="Transparent"
  4. PointerEntered="canvas_PointerEntered"
  5. PointerPressed="canvas_PointerPressed"
  6. PointerMoved="canvas_PointerMoved"
  7. PointerExited="canvas_PointerExited">
  8. </Canvas>
  9. </Grid>
  10.  
  11. <Page.BottomAppBar>
  12. <CommandBar IsOpen="False">
  13. <CommandBar.PrimaryCommands>
  14. <AppBarButton Icon="Back" Label="撤销" Click="AppBarButton_Click"></AppBarButton>
  15. <AppBarButton Icon="FontColor" Label="颜色">
  16. <AppBarButton.Flyout>
  17. <Flyout x:Name="colorflyout">
  18. <ListView x:Name="colorlv" IsItemClickEnabled="True" ItemClick="colorlv_ItemClick" >
  19. <ListView.ItemTemplate>
  20. <DataTemplate>
  21. <TextBlock FontSize="12" Text="{Binding}"></TextBlock>
  22. </DataTemplate>
  23. </ListView.ItemTemplate>
  24. </ListView>
  25. </Flyout>
  26. </AppBarButton.Flyout>
  27. </AppBarButton>
  28. <AppBarButton Icon="FontSize" Label="字体">
  29. <AppBarButton.Flyout>
  30. <Flyout x:Name="fontflyout" >
  31. <Slider x:Name="fontslider" Width="100" Minimum="2" Maximum="15" SmallChange="1"
    Orientation="Horizontal" ValueChanged="Slider_ValueChanged" ></Slider>
  32. </Flyout>
  33. </AppBarButton.Flyout>
  34. </AppBarButton>
  35. </CommandBar.PrimaryCommands>
  36. </CommandBar>
  37. </Page.BottomAppBar>

C#代码:

下面这段代码主要用来画线,涉及到PointerPressed和PointerMoved事件。

  1. private void canvas_PointerPressed(object sender, PointerRoutedEventArgs e)
  2. {
  3. currentPoint = e.GetCurrentPoint(canvas).Position;
  4. lastPoint = currentPoint;
  5. }
  6.  
  7. private void canvas_PointerMoved(object sender, PointerRoutedEventArgs e)
  8. {
  9. currentPoint = e.GetCurrentPoint(canvas).Position;
  10.  
  11. Line line = new Line() { X1 = currentPoint.X, Y1 = currentPoint.Y, X2 = lastPoint.X, Y2 = lastPoint.Y };
  12. line.Stroke = new SolidColorBrush(color);
  13. line.StrokeThickness = fontsize;
  14. line.StrokeLineJoin = PenLineJoin.Round;
  15. line.StrokeStartLineCap = PenLineCap.Round;
  16. line.StrokeEndLineCap = PenLineCap.Round;
  17. this.canvas.Children.Add(line);
  18. lastPoint = currentPoint;
  19. lineCount++;
  20. }

接着,我们考虑一下,该如何删除最后画在屏幕上的那条线呢?你可能会想到这句代码this.canvas.Children.RemoveAt(this.canvas.Children.Count - 1);(如果用这句代码,你可能要点很多下撤销按钮才能删除最后那条线),然而我们从上面可以知道,只要手指有滑动,就会不断触发PointerMoved事件,每次触发这个事件都会画一条线,只是那些线都首尾相接了,所以我们最后画在屏幕上的那条线其实是一系列的线首尾相接而成。具体的删除方法,请看下面的代码:

  1. private void canvas_PointerEntered(object sender, PointerRoutedEventArgs e)
  2. {
  3. lineCount = ;
  4. }
  5. private void canvas_PointerExited(object sender, PointerRoutedEventArgs e)
  6. {
  7. lineCountList.Add(lineCount);
  8. }
  9. private void AppBarButton_Click(object sender, RoutedEventArgs e)
  10. {
  11. if (lineCountList.Count > )
  12. {
  13. int lines = lineCountList[lineCountList.Count - ];
  14. for (int i = ; i < lines; i++)
  15. {
  16. this.canvas.Children.RemoveAt(this.canvas.Children.Count - );
  17. }
  18. lineCountList.RemoveAt(lineCountList.Count - );
  19. }
  20. }

lineCount是定义在MainPage类中的变量(用来记录在PointerMoved中画的线的条数,也就是我们最近在屏幕上画的那条线实际包含线的条数),我们在PointerEntered给lineCount赋初值0,然后在PointerMoved里面执行加1操作,最后在PointerExited事件中将lineCount添加到集合lineCountList中进行保存,然后在AppBarButton_Click中进行具体的删除。至于一下删除所有,那就直接 canvas.Children.Clear();

颜色设置和字号设置的代码很简单就不贴了,下面来看图吧。我们这个示例最好在手机上调试,PC的话,只要鼠标在应用程序的区域移动就会画线,有点烦人。

 

2.操作事件

如果需要在应用中支持多个手指或速度数据的交互,则要使用操作事件。我们还可以使用操作事件来检测拖动、缩放和按住之类的交互。下表是操作事件及其相关的事件参数。

事件或类 描述
ManipulationStarting event 首次创建操作处理器时发生。
ManipulationStarted event 当输入设备在 UIElement 上开始操作时发生。
ManipulationDelta event 当输入设备在操作期间更改位置时发生。
ManipulationInertiaStarting event 在操作过程中,当延迟开始时,如果输入设备与 UIElement 对象失去联系,则会发生。
ManipulationCompleted event UIElement 上的操作和延迟完成时发生。
ManipulationStartingRoutedEventArgs 提供 ManipulationStarting 事件的数据。
ManipulationStartedRoutedEventArgs 提供 ManipulationStarted 事件的数据。
ManipulationDeltaRoutedEventArgs 提供 ManipulationDelta 事件的数据。
ManipulationInertiaStartingRoutedEventArgs 提供 ManipulationInertiaStarting 事件的数据。
ManipulationVelocities 描述操作发生的速度。
ManipulationCompletedRoutedEventArgs 提供 ManipulationCompleted 事件的数据。

我们的手势事件是由一系列操作事件组成。每个手势都是从ManipulationStarted事件开始,当用户触摸屏幕时,将会触发一个或多个ManipulationDelta事件,当手势完成用户手指离开屏幕时,会触发ManipulationCompleted事件。ManipulationStarting事件则是Manipulation系列事件最开始触发的事件,ManipulationInertialStarting事件则是在ManipulationDelta事件触发的过程中,如果有延迟则会发生,并不是必然会触发的事件。如下图所示:

在这些事件中,最重要的一个事件就是ManipulationDelta事件,相关手势的逻辑判断都要依赖于这个事件,而在一次触控当中,这个事件又可能被触发多次,和上面提到的PointerMoved事件类似,所以处理起来还是比较麻烦的。ManipulationDelta事件通过参数ManipulationDeltaRoutedEventArgs对象来传递相关的触摸和滑动信息,我们可以转到定义看一下这个类它所提供的一些属性,主要关注ManipulationDelta类型的两个属性Cumulative和Delta,Cumulative记录自开始操作之后的全部更改,Delta则是当前操作的最近更改。ManipulationDelta类,我们也可以转到定义看一下, 有System.Single(单精度浮点类型)类型的三个参数:Expansion(触摸触点间的距离更改,以DIP表示)、Rotation(旋转角度的变化,以度为单位)、Scale(触摸触点间的距离更改,以百分比表示)和Point类型的Translation(表示平移距离)。

另外,我们在使用Manipulation系列事件的时候,还需要设置ManipulationMode属性,其值为ManipulationModes枚举,具体的枚举值我们可以转到定义进行查看。

(实例实例,,,,请看下回。。。。)

操作事件,尤其是ManipulationDelta事件用得还是比较多的,然后这一部分的内容也是有一定的难度,需要重点掌握一下。由于准备不足,这部分的内容下次再继续讨论咯。好了,晚安!

本次内容的Demo链接:http://pan.baidu.com/s/1jHaa2BO 密码:5btc

Windows 10开发基础——指针事件和操作事件(一)的更多相关文章

  1. Windows 10开发基础——文件、文件夹和库(一)

    原文:Windows 10开发基础--文件.文件夹和库(一) 主要内容: 1.枚举查询文件和文件夹 2.文本文件读写的三种方法——创建写入和读取文件 3.获得文件的属性 枚举查询文件和文件夹 先了解一 ...

  2. Windows 10开发基础——网络编程

    主要内容: HttpClient类 Socket通信 WCF通信 HttpClient类      在UWP中可以用来进行网络通信的HttpClient类有两个,System.Net.Http.Htt ...

  3. Windows 10开发基础——XML和JSON (二)

    主要内容: Linq to XML Newtonsoft.Json.Linq来解析JSON 博客园RSS(http://www.cnblogs.com/rss)的解析 UWP调用自己实现的Web AP ...

  4. Windows 10开发基础——XML和JSON (一)

    主要内容: JSON的序列化与反序列化 XML的序列化与反序列化 1.JSON的序列化与反序列化     JSON(JavaScript Object Notation)是一种轻量级的数据交换语言,它 ...

  5. Windows 10开发基础——VS2015 Update1新建UWP项目,XAML设计器无法加载的解决

    这次,我们来解决一个问题...在使用Visual Studio 2015 Update 1的时候,新建一个UWP的项目,XAML设计器就会崩,具体异常信息如下图: 解决方法如下:下面圈出的那个路径就按 ...

  6. Windows 10开发基础——文件、文件夹和库(二)

    主要内容: 使用选取器打开和保存文件 关于文件.文件夹和库,如果深究其实还是有比较多的内容,我们这一次来学习一下选取器就收了.还有上篇博文中读写文本文件的三种方式可以细细体会一下. 文件选取器包含文件 ...

  7. Windows 10开发基础——启动默认应用的URI

    主要内容:通过指定的URI来启动默认的应用(设置,应用商店,地图,人脉) 方法一:直接在XAML中添加如下代码 <TextBlock x:Name="LocationDisabledM ...

  8. Windows 10 开发人员预览版中的新增功能(转自 IT之家)

    Windows 10 开发人员预览版中的新增功能 在Win10预览版中安装工具与SDK后,即可着手创建Windows通用应用或先浏览目前的环境与此前相比都发生了什么变化. 应用建模 文件资源管理器: ...

  9. Windows驱动程序开发基础(四)驱动的编译调试和安装

    Windows驱动程序开发基础,转载标明出处:http://blog.csdn.net/ikerpeng/article/details/38793995 以下说一下开发出来驱动程序以后怎样编译.一般 ...

随机推荐

  1. [Compose] Isomorphisms and round trip data transformations

    What is Isomorphisms?We have a value x, then apply function 'to' and 'from' to value 'x', the result ...

  2. 30行js rem弹性布局适配所有分辨率

    <script> /* # 按照宽高比例设定html字体, width=device-width initial-scale=1版 # @pargam win 窗口window对象 # @ ...

  3. [TypeScript] Use the never type to avoid code with dead ends using TypeScript

    Example 1: A never stop while loop return a never type. function run(): never { while(true){ let foo ...

  4. [自学AndroidStudio系列]第二篇章:高速上手AS小技巧其一

    事实上看过第一篇的文章的人可能发现了,这个系列实际上是针对,有android开发经验的,之前使用Eclipse的开发人员;所以,避免无谓的口舌,直接进入说重点吧; 关闭项目自己主动打开 AS会自己主动 ...

  5. js进阶 11-1 jquery中的页面内容操作的三个方法

    jquery中的页面内容操作的三个方法 一.总结 一句话总结:记三个方法即可.text,html,val.因为这里是方法,所以设置值的是后面方法的参数. 1.jquery中的页面内容操作的三个方法? ...

  6. 创建数据库以及其属性的sql语句

    创建数据库的SQL语句: create database stuDB on primary -- 默认就属于primary文件组,可省略 ( /*--数据文件的详细描写叙述--*/ name='stu ...

  7. shell配置java环境变量和批处理配置环境变量

    linux配置java环境只需在/etc/profile中添加以下 前提是把jdk解压到/usr/local路径,当然路径可以随便改 export JAVA_HOME=/usr/local/jdk1. ...

  8. Maven项目中读取src/main/resources目录下的配置文件

    在Maven项目的开发中,当需要读取src/下的配置文件时,该怎么做? 我们假设Resources下有一个文件名为kafka.properties的配置文件(为什么用kafka.properties, ...

  9. Android - HelloWorld的Layout内容

    Android - HelloWorld的Layout内容 本文地址: http://blog.csdn.net/caroline_wendy 作为最基础的Android程序, HelloWorld的 ...

  10. Delphi png、bmp、gif等图片格式转换成jpg

    unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms ...