欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

背水一战 Windows 10 (69) - 控件(控件基类): UIElement - Manipulate 手势处理, 路由事件的注册, 路由事件的冒泡,

程序员文章站 2022-06-24 09:06:28
背水一战 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
[源码下载]