posts - 563, comments - 10438, trackbacks - 594, articles - 0
  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理

公告

背水一战 Windows 10 (68) - 控件(控件基类): UIElement - Pointer 相关事件, Tap 相关事件, Key 相关事件, Focus 相关事件

Posted on 2017-10-12 08:30 webabcd 阅读(...) 评论(...) 编辑 收藏

[源码下载]


背水一战 Windows 10 (68) - 控件(控件基类): UIElement - Pointer 相关事件, Tap 相关事件, Key 相关事件, Focus 相关事件



作者:webabcd


介绍
背水一战 Windows 10 之 控件(控件基类 - UIElement )

  • Pointer 相关事件
  • Tap 相关事件
  • Key 相关事件
  • Focus 相关事件



示例
1、演示 Pointer 相关事件
Controls/BaseControl/UIElementDemo/PointerDemo.xaml

<Page
    x:Class="Windows10.Controls.BaseControl.UIElementDemo.PointerDemo"
    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">

            <Rectangle Name="rectangle" Width="400" Height="100" Fill="Orange" HorizontalAlignment="Left" VerticalAlignment="Top" />

            <ScrollViewer Margin="0 110 0 10" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
                <TextBlock Name="lblMsg" TextWrapping="Wrap" />
            </ScrollViewer>

        </Grid>
    </Grid>
</Page>

Controls/BaseControl/UIElementDemo/PointerDemo.xaml.cs

/*
 * UIElement - UIElement(继承自 DependencyObject, 请参见 /Controls/BaseControl/DependencyObjectDemo/)
 *     PointerEntered - 指针进入时触发的事件
 *     PointerExited - 指针离开时触发的事件
 *     PointerPressed - 指针按下时触发的事件
 *     PointerReleased -  指针释放时触发的事件
 *     PointerCanceled - 接触中的指针异常地失去接触时触发的事件(比如修改分辨率,用户注销等)
 *         所以要注意:PointerPressed 和 PointerReleased 也许并不会成对出现,因为如果触发了 PointerCanceled 则不会再触发 PointerReleased
 *     PointerMoved - 指针移动时触发的事件
 *     PointerWheelChanged - 滚轮操作时触发的事件
 *     PointerCaptureLost - 指针捕获丢失时触发的事件
 *     CapturePointer(Pointer value) - 捕获此 UIElement 上的指针,即在 UIElement 之外也可以响应 PointerReleased 事件
 *     ReleasePointerCapture(Pointer value) - 释放此 UIElement 上的指定指针的捕获
 *     ReleasePointerCaptures() - 释放此 UIElement 上的全部指针的捕获
 *     IReadOnlyList<Pointer> PointerCaptures - 获取此 UIElement 上的被捕获的指针集合
 * 
 * 
 * PointerRoutedEventArgs - 指针路由事件的事件参数
 *     OriginalSource - 引发此路由事件的对象
 *     Handled - 是否将事件标记为已处理
 *     KeyModifiers - 获取当前按下的辅助键(Windows.System.VirtualKeyModifiers 枚举)
 *         None, Control, Menu, Shift, Windows
 *     Pointer - 获取 Pointer 对象
 *         Pointer.PointerDeviceType - 指针设备的类型(Touch, Pen, Mouse)
 *         Pointer.PointerId - 指针标识,可以根据此属性来区分多点触摸场景下的不同指针或者不同设备的指针
 *     GetCurrentPoint(UIElement relativeTo) - 返回当前指针相对于指定元素的 PointerPoint 对象
 *         PointerPoint.Position -  指针的位置
 *         PointerPoint.Properties - 返回 PointerPointProperties 对象,有一堆 PointerPoint 的相关属性(示例中有说明)
 *     GetIntermediatePoints(UIElement relativeTo) - 返回当前指针相对于指定元素的 PointerPoint 对象的全部历史记录集合
 *    
 *    
 * 本例用于演示 UIElement 的 Pointer 相关事件的应用
 * 
 * 
 * 注:关于 Manipulate Pointer Tap 的区别如下
 * 1、Manipulate 是最底层,Pointer 在中间,Tap 是最高层,所以会先走 Manipulate 事件,再走 Pointer 事件,最后走 Tap 事件
 * 2、如果高层的事件被触发,最相对于它的底层的事件也会被触发,反之则不一定
 * 3、使用原则是能在高层处理的事件尽量在高层处理(开发会简单些)
 */

using System;
using Windows.UI.Core;
using Windows.UI.Input;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Shapes;

namespace Windows10.Controls.BaseControl.UIElementDemo
{
    public sealed partial class PointerDemo : Page
    {
        public PointerDemo()
        {
            this.InitializeComponent();

            // 修改指针的样式
            // Window.Current.CoreWindow.PointerCursor = new CoreCursor(CoreCursorType.Cross, 1);

            rectangle.PointerEntered += rectangle_PointerEntered;
            rectangle.PointerExited += rectangle_PointerExited;
            rectangle.PointerPressed += rectangle_PointerPressed;
            rectangle.PointerReleased += rectangle_PointerReleased;
            rectangle.PointerMoved += rectangle_PointerMoved;
            rectangle.PointerWheelChanged += rectangle_PointerWheelChanged;
            rectangle.PointerCanceled += rectangle_PointerCanceled;
            rectangle.PointerCaptureLost += rectangle_PointerCaptureLost;
        }

        void rectangle_PointerCaptureLost(object sender, PointerRoutedEventArgs e)
        {
            lblMsg.Text += "PointerCaptureLost " + e.Pointer.PointerId;
            lblMsg.Text += Environment.NewLine;
        }

        void rectangle_PointerCanceled(object sender, PointerRoutedEventArgs e)
        {
            lblMsg.Text += "PointerCanceled " + e.Pointer.PointerId;
            lblMsg.Text += Environment.NewLine;
        }

        void rectangle_PointerWheelChanged(object sender, PointerRoutedEventArgs e)
        {
            // 判断鼠标滚轮的滚动方向
            lblMsg.Text += "PointerWheelChanged " + e.GetCurrentPoint(null).Properties.MouseWheelDelta;
            lblMsg.Text += Environment.NewLine;
        }

        void rectangle_PointerMoved(object sender, PointerRoutedEventArgs e)
        {
            // lblMsg.Text += "PointerMoved " + e.Pointer.PointerId;
            // lblMsg.Text += Environment.NewLine;
        }

        void rectangle_PointerReleased(object sender, PointerRoutedEventArgs e)
        {
            lblMsg.Text += "PointerReleased " + e.Pointer.PointerId;
            lblMsg.Text += Environment.NewLine;

            ((Rectangle)sender).ReleasePointerCapture(e.Pointer);
        }

        void rectangle_PointerPressed(object sender, PointerRoutedEventArgs e)
        {
            lblMsg.Text += "PointerPressed " + e.Pointer.PointerId;
            lblMsg.Text += Environment.NewLine;

            bool hasCapture = ((Rectangle)sender).CapturePointer(e.Pointer);
            lblMsg.Text += "Got Capture: " + hasCapture;
            lblMsg.Text += Environment.NewLine;

            PointerPointProperties props = e.GetCurrentPoint(null).Properties;
            lblMsg.Text += "接触区域的边框: " + props.ContactRect.ToString();
            lblMsg.Text += Environment.NewLine;
            lblMsg.Text += "原始输入的边框: " + props.ContactRectRaw.ToString();
            lblMsg.Text += Environment.NewLine;
            lblMsg.Text += "触笔设备的筒状按钮是否按下: " + props.IsBarrelButtonPressed.ToString();
            lblMsg.Text += Environment.NewLine;
            lblMsg.Text += "输入是否已由指针设备取消: " + props.IsCanceled.ToString();
            lblMsg.Text += Environment.NewLine;
            lblMsg.Text += "输入是否来自橡皮擦: " + props.IsEraser.ToString();
            lblMsg.Text += Environment.NewLine;
            lblMsg.Text += "输入是否来自滚轮: " + props.IsHorizontalMouseWheel.ToString();
            lblMsg.Text += Environment.NewLine;
            lblMsg.Text += "指针是否在触摸屏的范围内: " + props.IsInRange.ToString();
            lblMsg.Text += Environment.NewLine;
            lblMsg.Text += "是否是反转的值: " + props.IsInverted.ToString();
            lblMsg.Text += Environment.NewLine;
            lblMsg.Text += "输入是否来自鼠标左键: " + props.IsLeftButtonPressed.ToString();
            lblMsg.Text += Environment.NewLine;
            lblMsg.Text += "输入是否来自鼠标中键: " + props.IsMiddleButtonPressed.ToString();
            lblMsg.Text += Environment.NewLine;
            lblMsg.Text += "输入是否来自鼠标右键: " + props.IsRightButtonPressed.ToString();
            lblMsg.Text += Environment.NewLine;
            lblMsg.Text += "输入是否来自主要指针: " + props.IsPrimary.ToString();
            lblMsg.Text += Environment.NewLine;
            lblMsg.Text += "第一个扩展按钮的按下状态: " + props.IsXButton1Pressed.ToString();
            lblMsg.Text += Environment.NewLine;
            lblMsg.Text += "第二个扩展按钮的按下状态: " + props.IsXButton2Pressed.ToString();
            lblMsg.Text += Environment.NewLine;
            lblMsg.Text += "指针施加到触摸屏上的力度(0.0-1.0): " + props.Pressure.ToString();
            lblMsg.Text += Environment.NewLine;
            lblMsg.Text += "触摸是否被拒绝了: " + props.TouchConfidence.ToString();
            lblMsg.Text += Environment.NewLine;
            lblMsg.Text += "指针状态的更改类型: " + props.PointerUpdateKind.ToString(); // PointerUpdateKind 枚举:LeftButtonPressed, LeftButtonReleased 等(详见文档)
            lblMsg.Text += Environment.NewLine;
            lblMsg.Text += "指针设备相关的 Orientation: " + props.Orientation.ToString();
            lblMsg.Text += Environment.NewLine;
            lblMsg.Text += "指针设备相关的 Twist: " + props.Twist.ToString();
            lblMsg.Text += Environment.NewLine;
            lblMsg.Text += "指针设备相关的 XTilt: " + props.XTilt.ToString();
            lblMsg.Text += Environment.NewLine;
            lblMsg.Text += "指针设备相关的 YTiltYTilt: " + props.YTilt.ToString();
            lblMsg.Text += Environment.NewLine;

            // 输入设备相关
            // props.HasUsage(uint usagePage, uint usageId)
            // props.GetUsageValue(uint usagePage, uint usageId)
        }

        void rectangle_PointerExited(object sender, PointerRoutedEventArgs e)
        {
            lblMsg.Text += "PointerExited " + e.Pointer.PointerId;
            lblMsg.Text += Environment.NewLine;
        }

        void rectangle_PointerEntered(object sender, PointerRoutedEventArgs e)
        {
            lblMsg.Text += "PointerEntered " + e.Pointer.PointerId;
            lblMsg.Text += Environment.NewLine;
        }
    }
}


2、演示 Tap  相关事件
Controls/BaseControl/UIElementDemo/TapDemo.xaml

<Page
    x:Class="Windows10.Controls.BaseControl.UIElementDemo.TapDemo"
    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">

            <Rectangle Name="rectangle" Width="400" Height="100" Fill="Orange" HorizontalAlignment="Left" Margin="5" />

            <TextBlock Name="lblMsg" TextWrapping="Wrap" Margin="5" />

        </StackPanel>
    </Grid>
</Page>

Controls/BaseControl/UIElementDemo/TapDemo.xaml.cs

/*
 * UIElement - UIElement(继承自 DependencyObject, 请参见 /Controls/BaseControl/DependencyObjectDemo/)
 *     IsTapEnabled, IsDoubleTapEnabled, IsRightTapEnabled, IsHoldingEnabled - 是否允许监听相关的事件
 *     Tapped, DoubleTapped, RightTapped, Holding - Tap 相关事件
 *     
 * TappedRoutedEventArgs - Tap 路由事件的事件参数
 *     Handled - 是否将事件标记为已处理
 *     PointerDeviceType - 指针设备的类型(Touch, Pen, Mouse)
 *     GetPosition(UIElement relativeTo) - 返回当前指针相对于指定元素的位置
 *     
 * DoubleTappedRoutedEventArgs - DoubleTap 路由事件的事件参数
 *     Handled - 是否将事件标记为已处理
 *     PointerDeviceType - 指针设备的类型(Touch, Pen, Mouse)
 *     GetPosition(UIElement relativeTo) - 返回当前指针相对于指定元素的位置
 *     
 * RightTappedRoutedEventArgs - RightTap 路由事件的事件参数
 *     Handled - 是否将事件标记为已处理
 *     PointerDeviceType - 指针设备的类型(Touch, Pen, Mouse)
 *     GetPosition(UIElement relativeTo) - 返回当前指针相对于指定元素的位置
 * 
 * HoldingRoutedEventArgs - Holding 路由事件的事件参数
 *     Handled - 是否将事件标记为已处理
 *     PointerDeviceType - 指针设备的类型(Touch, Pen, Mouse)
 *     GetPosition(UIElement relativeTo) - 返回当前指针相对于指定元素的位置
 *     HoldingState - Holding 状态(Windows.UI.Input.HoldingState 枚举)
 *         Started, Completed, Canceled
 *         
 *         
 * 本例用于演示 UIElement 的 Tap 相关事件的应用
 * 
 * 
 * 注:关于 Manipulate Pointer Tap 的区别如下
 * 1、Manipulate 是最底层,Pointer 在中间,Tap 是最高层,所以会先走 Manipulate 事件,再走 Pointer 事件,最后走 Tap 事件
 * 2、如果高层的事件被触发,最相对于它的底层的事件也会被触发,反之则不一定
 * 3、使用原则是能在高层处理的事件尽量在高层处理(开发会简单些)
 */

using System;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;

namespace Windows10.Controls.BaseControl.UIElementDemo
{
    public sealed partial class TapDemo : Page
    {
        public TapDemo()
        {
            this.InitializeComponent();

            rectangle.IsTapEnabled = true; // 默认值就是 true
            rectangle.IsDoubleTapEnabled = true; // 默认值就是 true
            rectangle.IsRightTapEnabled = true; // 默认值就是 true
            rectangle.IsHoldingEnabled = true; // 默认值就是 true

            rectangle.Tapped += rectangle_Tapped;
            rectangle.DoubleTapped += rectangle_DoubleTapped;
            rectangle.RightTapped += rectangle_RightTapped;
            rectangle.Holding += rectangle_Holding; // 鼠标操作时不会触发 Holding 事件
        }

        void rectangle_Holding(object sender, HoldingRoutedEventArgs e)
        {
            lblMsg.Text += "Holding";
            lblMsg.Text += Environment.NewLine;
        }

        void rectangle_RightTapped(object sender, RightTappedRoutedEventArgs e)
        {
            lblMsg.Text += "RightTapped";
            lblMsg.Text += Environment.NewLine;
        }

        void rectangle_DoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
        {
            lblMsg.Text += "DoubleTapped";
            lblMsg.Text += Environment.NewLine;
        }

        void rectangle_Tapped(object sender, TappedRoutedEventArgs e)
        {
            lblMsg.Text += "Tapped";
            lblMsg.Text += Environment.NewLine;
        }
    }
}


3、演示 Key  相关事件
Controls/BaseControl/UIElementDemo/KeyDemo.xaml

<Page
    x:Class="Windows10.Controls.BaseControl.UIElementDemo.KeyDemo"
    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">

        <TextBlock Name="lblMsg" Margin="5" />
        
        <TextBox Name="textBox" Margin="5 25 5 5" TextWrapping="Wrap" KeyDown="textBox_KeyDown" KeyUp="textBox_KeyUp" />

    </Grid>
</Page>

Controls/BaseControl/UIElementDemo/KeyDemo.xaml.cs

/*
 * UIElement - UIElement(继承自 DependencyObject, 请参见 /Controls/BaseControl/DependencyObjectDemo/)
 *     KeyDown - 按键按下时触发的事件
 *     KeyUp - 按键抬起时触发的事件
 * 
 * 
 * KeyRoutedEventArgs - 按键的事件参数
 *     Handled - 是否将事件标记为已处理
 *     Key - 按键枚举(比如 A, B, C, D, LeftControl 之类的,详细参见 VirtualKey 枚举)
 *     OriginalKey - 按键枚举(如果输入设备未映射到 Key 则可以通过此属性获取)
 *     KeyStatus - 按键的状态(一个 CorePhysicalKeyStatus 类型的对象,有好多字段,详细参见文档)
 *    
 * 
 * 注:全局键盘事件监听请参见:/Controls/BaseControl/DependencyObjectDemo/CoreDispatcherDemo.xaml.cs
 *    
 *    
 * 本例用于演示 UIElement 的 Key 相关事件的应用
 */

using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;

namespace Windows10.Controls.BaseControl.UIElementDemo
{
    public sealed partial class KeyDemo : Page
    {
        public KeyDemo()
        {
            this.InitializeComponent();
        }

        // 通过输入法输入是不会触发此事件的
        private void textBox_KeyDown(object sender, KeyRoutedEventArgs e)
        {
            lblMsg.Text = $"IsExtendedKey:{e.KeyStatus.IsExtendedKey}, IsKeyReleased:{e.KeyStatus.IsKeyReleased}, IsMenuKeyDown:{e.KeyStatus.IsMenuKeyDown}, RepeatCount:{e.KeyStatus.RepeatCount}, ScanCode:{e.KeyStatus.ScanCode}, WasKeyDown:{e.KeyStatus.WasKeyDown}";

            textBox.Text += e.Key.ToString();

            e.Handled = true;
        }

        // 通过输入法输入是不会触发此事件的
        private void textBox_KeyUp(object sender, KeyRoutedEventArgs e)
        {
            lblMsg.Text = $"IsExtendedKey:{e.KeyStatus.IsExtendedKey}, IsKeyReleased:{e.KeyStatus.IsKeyReleased}, IsMenuKeyDown:{e.KeyStatus.IsMenuKeyDown}, RepeatCount:{e.KeyStatus.RepeatCount}, ScanCode:{e.KeyStatus.ScanCode}, WasKeyDown:{e.KeyStatus.WasKeyDown}";

            e.Handled = true;
        }
    }
}



4、演示 Focus  相关事件
Controls/BaseControl/UIElementDemo/FocusDemo.xaml

<Page
    x:Class="Windows10.Controls.BaseControl.UIElementDemo.FocusDemo"
    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="5">

            <Button Name="button1" Content="button 1" Margin="5" />
            <Button Name="button2" Content="button 2" Margin="5" />

            <TextBlock Name="lblMsg" Margin="5" />
            
        </StackPanel>
    </Grid>
</Page>

Controls/BaseControl/UIElementDemo/FocusDemo.xaml.cs

/*
 * UIElement - UIElement(继承自 DependencyObject, 请参见 /Controls/BaseControl/DependencyObjectDemo/)
 *     GotFocus - 获取焦点时触发的事件(通过 api 获取焦点,或者通过鼠标获取焦点,或者通过 Tab 键获取焦点都会触发 GotFocus 事件)
 *     LostFocus - 丢失焦点时触发的事件
 *    
 *    
 * 本例用于演示 UIElement 的 Focus 相关事件的应用
 */

using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace Windows10.Controls.BaseControl.UIElementDemo
{
    public sealed partial class FocusDemo : Page
    {
        public FocusDemo()
        {
            this.InitializeComponent();

            button1.GotFocus += Button1_GotFocus;
            button1.LostFocus += Button1_LostFocus;

            button2.GotFocus += Button2_GotFocus;
            button2.LostFocus += Button2_LostFocus;

            this.Loaded += FocusDemo_Loaded;
        }

        private void FocusDemo_Loaded(object sender, RoutedEventArgs e)
        {
            // 通过 api 获取焦点
            button2.Focus(FocusState.Programmatic);
        }

        private void Button1_GotFocus(object sender, RoutedEventArgs e)
        {
            lblMsg.Text += "Button1_GotFocus";
            lblMsg.Text += Environment.NewLine;
        }

        private void Button1_LostFocus(object sender, RoutedEventArgs e)
        {
            lblMsg.Text += "Button1_LostFocus";
            lblMsg.Text += Environment.NewLine;
        }

        private void Button2_GotFocus(object sender, RoutedEventArgs e)
        {
            lblMsg.Text += "Button2_GotFocus";
            lblMsg.Text += Environment.NewLine;
        }

        private void Button2_LostFocus(object sender, RoutedEventArgs e)
        {
            lblMsg.Text += "Button2_LostFocus";
            lblMsg.Text += Environment.NewLine;
        }
    }
}



OK
[源码下载]