1. 程式人生 > >WPF 入門筆記之事件

WPF 入門筆記之事件

mar 選擇 直接 round 發生 頂部 路由事件 啟動 event

一、事件路由

1. 直接路由事件

  起源於一個元素,並且不能傳遞給其他元素

MouserEnter 和MouserLeave 就是直接事件路由

2. 冒泡路由事件

  在包含層次中向上傳遞,首先由引發的元素觸發,然後被父元素引發,直到到達WPF的元素樹的頂部位置

例如:MouserUp

以下控件都綁定了,MouseUp事件。根據輸出的順序表現冒泡路由的效果

<Window x:Class="Haos.WPF.Case.Event.BubbleRouteWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:Haos.WPF.Case.Event" mc:Ignorable="d" Title="BubbleRouteWindow"
Height="300" Width="300"> <!--冒泡路由--> <Grid Margin="3" MouseUp="SomethingClick"> <Grid.RowDefinitions> <RowDefinition Height="Auto"></RowDefinition> <RowDefinition Height="*"></RowDefinition> <RowDefinition
Height="Auto"></RowDefinition> <RowDefinition Height="Auto"></RowDefinition> </Grid.RowDefinitions> <Label Margin="5" Background="AliceBlue" BorderBrush="Black" BorderThickness="1" HorizontalAlignment="Center" Grid.Row="0" MouseUp="SomethingClick"> <StackPanel MouseUp="SomethingClick"> <TextBlock Margin="3" TextAlignment="Center" MouseUp="SomethingClick">Image and Picture Lable</TextBlock> <Image Source="/Images/logo_ye.png" Width="20" Stretch="Fill" MouseUp="SomethingClick"></Image> <TextBlock Margin="3" TextAlignment="Center" MouseUp="SomethingClick">Courtesy of the StackPanel</TextBlock> </StackPanel> </Label> <ListBox Margin="5" Name="lstMessage" Grid.Row="1"></ListBox> <CheckBox Margin="5" Grid.Row="2" Name="Check_Box">Handle first event</CheckBox> <Button Grid.Row="3" Margin="5" Padding="2" Click="Btn_Click">Clear List</Button> </Grid> </Window>
namespace Haos.WPF.Case.Event
{
    /// <summary>
    /// BubbleRouteWindow.xaml 的交互邏輯
    /// </summary>
    public partial class BubbleRouteWindow : Window
    {
        public BubbleRouteWindow()
        {
            InitializeComponent();
        }

        public int EventCounter = 0;

        /// <summary>
        /// MouseUp 的處理程序
        /// </summary>
        /// <param name="sender">觸發者</param>
        /// <param name="e">事件參數</param>
        private void SomethingClick(object sender, MouseButtonEventArgs e)
        {
            EventCounter++;
            string message = $"#{EventCounter}:\r\nSender:{sender.ToString()}\r\nSource:{e.Source}\r\nOriginal Source:{e.OriginalSource}";
            lstMessage.Items.Add(message);
            e.Handled = (bool)Check_Box.IsChecked;
        }

        private void Btn_Click(object sender, RoutedEventArgs e)
        {
            EventCounter = 0;
            lstMessage.Items.Clear();
        }
    }
}

3. 隧道路由事件

  在包含層次中向下傳遞,首先由WPF的元素樹的頂部觸發,然後向子元素引發,直到到達最後一個子元素

隧道路由的事件名稱以Preview開頭,例如PreviewKeyDown鍵盤按下事件

<Window x:Class="Haos.WPF.Case.Event.ChunnelRouteWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Haos.WPF.Case.Event"
        mc:Ignorable="d"
        Title="ChunnelRouteWindow" Height="300" Width="300" PreviewKeyDown="SomethingKeyUp">
        <!--隧道路由事件-->
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
        </Grid.RowDefinitions>
        <StackPanel Grid.Row="0" PreviewKeyDown="SomethingKeyUp">
            <TextBlock Margin="3" HorizontalAlignment="Center" PreviewKeyDown="SomethingKeyUp">Image and text Lable</TextBlock>
            <Image Source="/Images/logo_ye.png" Width="20" Stretch="Fill" PreviewKeyDown="SomethingKeyUp"></Image>
            <DockPanel PreviewKeyDown="SomethingKeyUp">
                <TextBlock PreviewKeyDown="SomethingKeyUp">Type here:</TextBlock>
                <TextBox PreviewKeyDown="SomethingKeyUp"></TextBox>
            </DockPanel>
        </StackPanel>
        <ListBox Margin="5" Name="lstMessage" Grid.Row="1"></ListBox>
        <CheckBox Margin="5" Grid.Row="2" Name="Check_Box">Handle first event</CheckBox>
        <Button Grid.Row="3" Margin="5" Padding="2" Click="Btn_Click">Clear List</Button>
    </Grid>
</Window>

二、事件類型

1. 生命周期事件

  1.1 Window.Initialized:在所有子元素都被設置完成時觸發

    這個元素已經被構建出來,並且它的屬性值都被設置好了,所以通常都是子元素先於父元素觸發這個事件.當一個元素的 Initialized 事件被觸發, 通常它的子樹都已經初始化完成, 但是父元素還未初始化. 這個事件通常是在子樹的 Xaml 被加載進來後觸發的. 這個事件與 IsInitialized 屬性相互綁定

  1.2 Window.Activated和Window.Deactivated:在窗口成為前臺窗口時發生(激活)/在窗口成為後臺窗口時發生

     戶在運行系統上的多個窗口中切換時,Activated和Deactivated在窗口的生命周期裏會發生多次

  1.3 Window.Loaded:在元素布局,呈現和準備交互時發生

    為了讓一些事情能在所有內容都顯示給用戶之前馬上執行,可以用Loaded事件

  1.4 Window.ContentRendered:在窗口的內容被渲染後發生

    ContentRendered事件只對窗口第一次完全呈現出來進行觸發。為了讓一些事情能在所有內容都顯示給用戶之後馬上執行,可以用ContentRendered事件

  1.5 Window.Closed:當窗口即將關閉時發生  

  1.6 Window.Closing:Closed之後立即發生 Close 被調用,並且可以處理以取消關閉窗口。

2.鼠標事件

2.1 捕獲鼠標坐標

捕獲鼠標相對,元素的位置

2.2 捕獲鼠標

當元素捕獲鼠標以後,其他元素就無法觸發其他元素上的,鼠標按鈕類事件。直到 Mouse.Capture(null);方法接受到一個null參數。

2.3 鼠標拖放輸入

用戶單擊或選擇元素上一塊區域,拖放動作開始,將鼠標移動到其他的元素上並且該元素可以接受拖放信息。

文本框自帶拖放功能。

首先設置鼠標按下事件時,綁定拖放的源。在放目標元素開啟,允許放屬性AllowDrop。同時綁定Drop事件處理放的操作

<Window x:Class="Haos.WPF.Case.Event.MouseEventWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Haos.WPF.Case.Event"
        mc:Ignorable="d"
        Title="MouseEventWindow" Height="300" Width="300">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
        </Grid.RowDefinitions>
        <!--獲取鼠標位置-->
        <Rectangle Name="rect" Fill="AliceBlue" MouseMove="Rect_Move"></Rectangle>
        <!--捕獲鼠標-->
        <Button Grid.Row="1" Name="Btn_Capture" Click="Capture_Click">Capture the Mouse</Button>
        <TextBlock Grid.Row="2" Name="Txt_Block">Mouse posstion at (0,0) in window coordinates</TextBlock>
        <DockPanel Grid.Row="3">
            <!--設置拖動的源-->
            <Label Background="DarkKhaki" Name="Txt_Scouce" MouseDown="Scouce_Down">this is label mouse</Label>
            <!--被放的對象,開啟允許拖放接受數據 AllowDrop="True"-->
            <Label Background="Aqua" AllowDrop="True" Name="Lbl_Drop" Drop="Lbl_Drops"></Label>
        </DockPanel>
    </Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace Haos.WPF.Case.Event
{
    /// <summary>
    /// MouseEventWindow.xaml 的交互邏輯
    /// </summary>
    public partial class MouseEventWindow : Window
    {
        public MouseEventWindow()
        {
            InitializeComponent();
        }
        /// <summary>
        /// 鼠標在矩形移動
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e">MouseEventArgs 不具備鼠標按鈕,鼠標滾輪的事件提供的參數</param>
        private void Rect_Move(object sender, MouseEventArgs e)
        {
            //獲取鼠標坐標
            Point point = e.GetPosition(this);
            Txt_Block.Text = $"Mouse posstion at ({point.X},{point.Y}) in window coordinates";
            if (point.X == 0)
            {
                //讓被捕獲的鼠標釋放
                Mouse.Capture(null);
            }
        }

        private void Capture_Click(object sender, RoutedEventArgs e)
        {
            Mouse.Capture(rect);
            Btn_Capture.Content = "鼠標被捕獲…";
        }

        /// <summary>
        /// 鼠標按下設置,拖放的源
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Scouce_Down(object sender, MouseButtonEventArgs e)
        {
            Label lbl = sender as Label; ;
            //啟動拖動
            DragDrop.DoDragDrop(lbl, lbl.Content, DragDropEffects.Copy);
        }
        /// <summary>
        /// 拖放,放的事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Lbl_Drops(object sender, DragEventArgs e)
        {
            Label lbl = sender as Label;
            lbl.Content = e.Data.GetData(DataFormats.Text);
        }
    }
}

3.鍵盤事件

  按照執行順序排列如下

  3.1 PreviewKeyDown:隧道鍵盤按下

  3.2 KeyDown:冒泡鍵盤按下

  3.3 PreviewTextInput:文本正在輸入事件

  3.4 TextChanged:本文框值發生改變

  3.5 PreviewKeyUp:隧道鍵盤彈起

  3.6 KeyUp:冒泡鍵盤彈起

<Window x:Class="Haos.WPF.Case.Event.KeyboardEventWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Haos.WPF.Case.Event"
        mc:Ignorable="d"
        Title="KeyboardEventWindow" Height="300" Width="300">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
        </Grid.RowDefinitions>
        <DockPanel Margin="5" Grid.Row="0">
            <TextBlock Margin="3">Type here:</TextBlock>
            <TextBox Focusable="True" PreviewKeyDown="KeyEvent" KeyDown="KeyEvent" PreviewKeyUp="KeyEvent" KeyUp="KeyEvent" PreviewTextInput="TextBox_PreviewTextInput" TextChanged="TextBox_TextChanged"></TextBox>
        </DockPanel>
        <ListBox Margin="5" Grid.Row="1" Name="lstMessage"></ListBox>
        <Button Grid.Row="2" Name="Btn_Clear" Padding="3" Margin="3" Click="Btn_Clear_Click">Clear ListBox</Button>
    </Grid>
</Window>
namespace Haos.WPF.Case.Event
{
    /// <summary>
    /// KeyboardEventWindow.xaml 的交互邏輯
    /// </summary>
    public partial class KeyboardEventWindow : Window
    {
        public KeyboardEventWindow()
        {
            InitializeComponent();
        }
        
        private void TextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
        {
            string message = $"Event:{e.RoutedEvent} Key:{e.Text}";
            lstMessage.Items.Add(message);
        }

        private void KeyEvent(object sender, KeyEventArgs e)
        {
            string message = $"Event:{e.RoutedEvent} Key:{e.Key}";
            lstMessage.Items.Add(message);
        }

        private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            string message = $"Event:{e.RoutedEvent}";
            lstMessage.Items.Add(message);
        }

        private void Btn_Clear_Click(object sender, RoutedEventArgs e)
        {
            lstMessage.Items.Clear();
        }
    }
}

  3.7 焦點相關:

    Focusable設置控件是否能夠獲得焦點,和TabIndex屬性設置按下Tab鍵獲得焦點的順序。在WPF中是使用樹形結構布局的,所以當按下Tab鍵時,焦點會移動到當前元素的一個子元素。如果沒有子元素,會移動到同級下一個元素的第一個子元素

4.手寫筆事件

5.多點觸控事件

WPF 入門筆記之事件