背水一战 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
[源码下载]