1. 程式人生 > >背水一戰 Windows 10 (68) - 控件(控件基類): UIElement - Pointer 相關事件, Tap 相關事件, Key 相關事件, Focus 相關事件

背水一戰 Windows 10 (68) - 控件(控件基類): UIElement - Pointer 相關事件, Tap 相關事件, Key 相關事件, Focus 相關事件

tar release 關於 場景 npr 相對 capture soft etc

[源碼下載]


背水一戰 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
[源碼下載]

背水一戰 Windows 10 (68) - 控件(控件基類): UIElement - Pointer 相關事件, Tap 相關事件, Key 相關事件, Focus 相關事件