背水一战 Windows 10 (69) - 控件(控件基类): UIElement - Manipulate 手势处理, 路由事件的注册, 路由事件的冒泡, 命中测试的可见性
背水一战 Windows 10 (69) - 控件(控件基类): UIElement - Manipulate 手势处理, 路由事件的注册, 路由事件的冒泡, 命中测试的可见性
作者:webabcd
介绍
背水一战 Windows 10 之 控件(控件基类 - UIElement)
- Manipulate 手势处理
- 路由事件的注册
- 路由事件的冒泡
- 命中测试的可见
示例
1、演示 Manipulate 手势处理
Controls/BaseControl/UIElementDemo/ManipulateDemo.xaml
<Page x:Class="Windows10.Controls.BaseControl.UIElementDemo.ManipulateDemo" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:Windows10.Controls.BaseControl.UIElementDemo" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid Background="Transparent"> <Grid Margin="10 0 10 10"> <TextBlock Name="lblMsg" Margin="5" /> <Rectangle Name="rectangle" Height="200" Width="200" Fill="Orange" Margin="5" /> </Grid> </Grid> </Page>
Controls/BaseControl/UIElementDemo/ManipulateDemo.xaml.cs
/* * UIElement - UIElement(继承自 DependencyObject, 请参见 /Controls/BaseControl/DependencyObjectDemo/) * ManipulationModes - 需要监测的手势(Windows.UI.Xaml.Input.ManipulationModes 枚举) * None - 禁用手势监测 * TranslateX, TranslateY - 位移手势 * TranslateRailsX, TranslateRailsY - 带有轨道的位移手势 * Rotate - 旋转手势 * Scale - 缩放手势 * TranslateInertia - 带有惯性的位移手势 * RotateInertia - 带有惯性的旋转手势 * ScaleInertia - 带有惯性的缩放手势 * All - 监测全部手势 * ManipulationStarting - 触控操作开始时触发的事件 * ManipulationStarted - 触控操作开始后触发的事件 * ManipulationInertiaStarting - 触控操作的惯性开始时触发的事件 * ManipulationCompleted - 触控操作结束后触发的事件 * ManipulationDelta - 触控值发生变化时触发的事件 * * ManipulationStartingRoutedEventArgs * Container - 此 Manipulation 的容器 * Mode - 获取或设置 ManipulationModes * Pivot - 获取或设置轴对象,ManipulationPivot 类型的数据 * Center - 旋转中心点 * Radius - 有效的旋转半径 * * ManipulationStartedRoutedEventArgs * Container - 此 Manipulation 的容器 * Cumulative - 自操作开始后的累计变化量,返回 ManipulationDelta 类型的对象 * Position - 触摸点相对于 UIElement 的位置 * Complete() - 马上完成 Manipulation 而不发生惯性 * * ManipulationDeltaRoutedEventArgs * Container - 此 Manipulation 的容器 * Cumulative - 自操作开始后的累计变化量,返回 ManipulationDelta 类型的对象 * Delta - 当前变化量,返回 ManipulationDelta 类型的对象 * Velocities - 当前变化的速率,返回 ManipulationVelocities 类型的对象 * IsInertial - 是否在惯性运动之中 * Position - 触摸点相对于 UIElement 的位置 * Complete() - 马上完成 Manipulation 而不发生惯性 * * ManipulationInertiaStartingRoutedEventArgs * Container - 此 Manipulation 的容器 * Cumulative - 自操作开始后的累计变化量,返回 ManipulationDelta 类型的对象 * Delta - 当前变化量,返回 ManipulationDelta 类型的对象 * Velocities - 当前变化的速率,返回 ManipulationVelocities 类型的对象 * ExpansionBehavior - 惯性的缩放行为,获取或设置 InertiaExpansionBehavior 类型的对象 * DesiredDeceleration - 惯性运动时,缩放的减慢速率 * DesiredExpansion - 惯性结束后,缩放的值 * RotationBehavior - 惯性的旋转行为,获取或设置 InertiaRotationBehavior 类型的对象 * DesiredDeceleration - 惯性运动时,旋转的减慢速率 * DesiredRotation - 惯性结束后,旋转的度数 * TranslationBehavior - 惯性的位移行为,获取或设置 InertiaTranslationBehavior 类型的对象 * DesiredDeceleration - 惯性运动时,直线位移的减慢速率 * DesiredDisplacement - 惯性结束后,直线位移的的值 * * ManipulationCompletedRoutedEventArgs * Container - 此 Manipulation 的容器 * Cumulative - 自操作开始后的累计变化量,返回 ManipulationDelta 类型的对象 * Velocities - 当前变化的速率,返回 ManipulationVelocities 类型的对象 * IsInertial - 结束前是否发生了惯性运动 * Position - 触摸点相对于 UIElement 的位置 * ManipulationDelta - 变化量 * Expansion - 触摸点间距离的变化,单位 dip * Scale - 触摸点间距离的变化,以一个百分比表示 * Rotation - 旋转角度的变化,以角度为单位 * Translation - 位移的变化,Point 类型的对象 * ManipulationVelocities - 变化速率 * Angular - 旋转速度,单位:度/毫秒 * Expansion - 缩放速度,单位:dip/毫秒 * Linear - 直线位移速度,单位:Point/毫秒 * * * 什么是 dip: device independent pixels(设备独立像素),不管屏大小和分辨率,把屏幕分成 480 * 320 个点,其中每一点代表 1 dip * Manipulate 是 UIElement 级别的手势操作;GestureRecognizer 是 app 级别的手势识别 * * * 本例用于演示 UIElement 的 Manipulate 的应用(位移手势,缩放手势,旋转手势) * * * 注:关于 Manipulate Pointer Tap 的区别如下 * 1、Manipulate 是最底层,Pointer 在中间,Tap 是最高层,所以会先走 Manipulate 事件,再走 Pointer 事件,最后走 Tap 事件 * 2、如果高层的事件被触发,最相对于它的底层的事件也会被触发,反之则不一定 * 3、使用原则是能在高层处理的事件尽量在高层处理(开发会简单些) */ using System; using Windows.Foundation; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; namespace Windows10.Controls.BaseControl.UIElementDemo { public sealed partial class ManipulateDemo : Page { private TransformGroup _transformGroup; private CompositeTransform _compositeTransform; private MatrixTransform _previousTransform; public ManipulateDemo() { this.InitializeComponent(); // 监测全部手势 rectangle.ManipulationMode = ManipulationModes.All; // 仅监测旋转手势和缩放手势 // rectangle.ManipulationMode = ManipulationModes.Rotate | ManipulationModes.Scale; _transformGroup = new TransformGroup(); _compositeTransform = new CompositeTransform(); _previousTransform = new MatrixTransform() { Matrix = Matrix.Identity }; _transformGroup.Children.Add(_previousTransform); _transformGroup.Children.Add(_compositeTransform); rectangle.RenderTransform = _transformGroup; rectangle.ManipulationStarting += rectangle_ManipulationStarting; rectangle.ManipulationStarted += rectangle_ManipulationStarted; rectangle.ManipulationInertiaStarting += rectangle_ManipulationInertiaStarting; rectangle.ManipulationCompleted += rectangle_ManipulationCompleted; rectangle.ManipulationDelta += rectangle_ManipulationDelta; } void rectangle_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e) { _previousTransform.Matrix = _transformGroup.Value; // 获取操作点相对于此 GeneralTransform 的位置 Point center = _previousTransform.TransformPoint(new Point(e.Position.X, e.Position.Y)); _compositeTransform.CenterX = center.X; _compositeTransform.CenterY = center.Y; _compositeTransform.Rotation = e.Delta.Rotation; _compositeTransform.ScaleX = e.Delta.Scale; _compositeTransform.ScaleY = e.Delta.Scale; _compositeTransform.TranslateX = e.Delta.Translation.X; _compositeTransform.TranslateY = e.Delta.Translation.Y; } void rectangle_ManipulationStarting(object sender, ManipulationStartingRoutedEventArgs e) { lblMsg.Text += "ManipulationStarting"; lblMsg.Text += Environment.NewLine; } void rectangle_ManipulationStarted(object sender, ManipulationStartedRoutedEventArgs e) { lblMsg.Text += "ManipulationStarted"; lblMsg.Text += Environment.NewLine; } void rectangle_ManipulationInertiaStarting(object sender, ManipulationInertiaStartingRoutedEventArgs e) { lblMsg.Text += "ManipulationInertiaStarting"; lblMsg.Text += Environment.NewLine; } void rectangle_ManipulationCompleted(object sender, ManipulationCompletedRoutedEventArgs e) { lblMsg.Text += "ManipulationCompleted"; lblMsg.Text += Environment.NewLine; } } }
2、演示路由事件的注册, 路由事件的冒泡, 命中测试的可见性
Controls/BaseControl/UIElementDemo/EventDemo.xaml
<Page x:Class="Windows10.Controls.BaseControl.UIElementDemo.EventDemo" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:Windows10.Controls.BaseControl.UIElementDemo" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid Background="Transparent"> <StackPanel Margin="10 0 10 10"> <Grid HorizontalAlignment="Left" VerticalAlignment="Top" Margin="5"> <!-- 演示事件冒泡:儿子传递事件给爸爸,爸爸传递事件给爷爷,这就是事件冒泡 --> <Border Name="borderRed" Background="Red" Width="300" Height="300"> <Border Name="borderGreen" Background="Green" Width="250" Height="250" Tapped="borderGreen_Tapped"> <Border Name="borderBlue" Background="Blue" Width="200" Height="200" Tapped="borderBlue_Tapped"> <Border Name="borderOrange" Background="Orange" Width="150" Height="150" Tapped="borderOrange_Tapped"> <!--通过 IsHitTestVisible="False" 设置命中测试不可见,也就是说 borderPurple 和 borderYellow 均命中测试不可见--> <Border Name="borderPurple" Background="Purple" Width="100" Height="100" Tapped="borderPurple_Tapped" IsHitTestVisible="False"> <Border Name="borderYellow" Background="Yellow" Width="50" Height="50" Tapped="borderYellow_Tapped" /> </Border> </Border> </Border> </Border> </Border> <!-- 像这样排列元素,是没有事件冒泡的,而只是前面的元素响应事件,后面的元素不会响应事件,也就是说同辈间没有事件冒泡的概念 IsHitTestVisible - 是否对命中测试可见(如果需要后面的元素响应事件,而前面的元素不响应事件,则只需要把前面的元素的命中测试设置为不可见即可) <Rectangle Name="rectangle1" Width="200" Height="200" Fill="Red" /> <Rectangle Name="rectangle2" Width="200" Height="200" Fill="Green" /> <Rectangle Name="rectangle3" Width="200" Height="200" Fill="Blue" /> <Rectangle Name="rectangle4" Width="200" Height="200" Fill="Orange" /> <Rectangle Name="rectangle5" Width="200" Height="200" Fill="Purple" /> --> </Grid> <TextBlock Name="lblMsg" Margin="5" /> </StackPanel> </Grid> </Page>
Controls/BaseControl/UIElementDemo/EventDemo.xaml.cs
/* * UIElement - UIElement(继承自 DependencyObject, 请参见 /Controls/BaseControl/DependencyObjectDemo/) * IsHitTestVisible - 是否对命中测试可见 * AddHandler(RoutedEvent routedEvent, object handler, bool handledEventsToo) - 注册一个路由事件,注意最后一个参数:true 代表即使子辈 TappedRoutedEventArgs.Handled = true 也不会影响此元素事件的触发 * RemoveHandler(RoutedEvent routedEvent, object handler) - 移除指定的路由事件 * * * RoutedEventArgs - 路由事件参数(有 n 多的派生类) * OriginalSource - 引发此路由事件的对象 * * TappedRoutedEventArgs - Tapped 事件参数(继承自 RoutedEventArgs,详细说明请参见 /Controls/BaseControl/DependencyObjectDemo/TapDemo.xaml) * Handled - 是否将路由事件标记为已处理 * true - 不再冒泡 * false - 继续冒泡 * * * 本例用于演示 UIElement 的路由事件的注册,路由事件的冒泡,命中测试的可见性 */ using System; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Input; namespace Windows10.Controls.BaseControl.UIElementDemo { public sealed partial class EventDemo : Page { public EventDemo() { this.InitializeComponent(); // 为 borderRed 注册一个 TappedEventHandler 路由事件(注意最后一个参数:true 代表即使子辈 TappedRoutedEventArgs.Handled = true 也不会影响此元素事件的触发) borderRed.AddHandler(UIElement.TappedEvent, new TappedEventHandler(borderRed_Tapped), true); } private void borderRed_Tapped(object sender, TappedRoutedEventArgs e) { lblMsg.Text += "borderRed tapped, originalSource: " + (e.OriginalSource as FrameworkElement).Name; lblMsg.Text += Environment.NewLine; } private void borderGreen_Tapped(object sender, TappedRoutedEventArgs e) { lblMsg.Text += "borderGreen tapped, originalSource: " + (e.OriginalSource as FrameworkElement).Name; lblMsg.Text += Environment.NewLine; } private void borderBlue_Tapped(object sender, TappedRoutedEventArgs e) { lblMsg.Text += "borderBlue tapped, originalSource: " + (e.OriginalSource as FrameworkElement).Name; lblMsg.Text += Environment.NewLine; // 不会再冒泡,也就是说 borderGreen 无法响应 Tapped 事件,但是 borderRed 注册 Tapped 事件时 handledEventsToo = true,所以 borderRed 会响应 Tapped 事件 e.Handled = true; } private void borderOrange_Tapped(object sender, TappedRoutedEventArgs e) { lblMsg.Text += "borderOrange tapped, originalSource: " + (e.OriginalSource as FrameworkElement).Name; lblMsg.Text += Environment.NewLine; } private void borderPurple_Tapped(object sender, TappedRoutedEventArgs e) { // 不会响应此事件,因为 borderPurple 的 IsHitTestVisible = false lblMsg.Text += "borderPurple tapped, originalSource: " + (e.OriginalSource as FrameworkElement).Name; lblMsg.Text += Environment.NewLine; } private void borderYellow_Tapped(object sender, TappedRoutedEventArgs e) { // 不会响应此事件,因为 borderYellow 的爸爸 borderPurple 的 IsHitTestVisible = false lblMsg.Text += "borderYellow tapped, originalSource: " + (e.OriginalSource as FrameworkElement).Name; lblMsg.Text += Environment.NewLine; } } }
OK
[源码下载]