背水一戰 Windows 10 之 控制項(控制項基類 - 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
[源碼下載]