WPF中事件的类型有两种:①普通.NET事件 ②路由事件
WPF事件一共有五类:①生命周期事件 ②鼠标事件 ③键盘事件 ④手写笔事件 ⑤触控事件
这些事件支持着WPF程序的运作。
生命周期事件
FrameworkElement类中定义的三个生命周期事件
Initialized--普通.NET事件,元素实例化并设置了属性之后发生,即元素初始化完成。判断属性IsInitialized
Loaded--样式应用和数据绑定的完成,元素呈现之前的最后一步发生。判断属性IsLoaded
Unloaded--元素被释放时发生
在Initialized之前,还存在ISupportInitialize接口的两个方法的执行:BeginInit()和EndInit()
页面初始化和加载流程
在最开始创建页面时,初始化行为是由内而外的,由子及父的,直至引发到最外层元素(例如窗口),即触发了最外层元素的Initialized事件,完成初始化过程。
然后引发加载流程,加载行为是由外而内的,由父及子的,直至加载完所有元素,即触发了所有元素的Loaded事件,至此页面完整呈现。
Window类的生命周期事件
输入事件
通过继承InputEventArgs的事件参数类传递额外的信息,InputEventArgs也是继承自RoutedEventArgs
InputEventArgs的两个属性:Timestamp和Device
键盘输入
当按下键盘时,会发生一系列的事件,控件不同触发的事件也会不同。
比如PreviewKeyDown->KeyDown->PreviewTextInput->TextInput->PreviewKeyUp->KeyUp
<TextBox TextInput="TextBox_TextInput" KeyDown="TextBox_KeyDown"/>
/// <summary>
/// 文本输入事件 TextInput
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void TextBox_TextInput(object sender, TextCompositionEventArgs e)
{
//TextInput事件从Text中获取控件即将接收到的文本
var txt = e.Text;
var eventObj = e.RoutedEvent;
}
/// <summary>
/// 键盘按键事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void TextBox_KeyDown(object sender, KeyEventArgs e)
{
//KeyDown / Up一类的事件都是从KeyEventArgs对象中,可以获取e.Key、e.IsRepeat,判断键入的Key值和是否重复。
var k = e.Key;
var r = e.IsRepeat;
}
根据实体键盘,可能会有同值但不同按键的情况,如Key.D7和Key.NumPad7,可以通过KeyConverter.ConverterToString()获得数字9
在PreviewTextInput中e.Text接收不到某些按键(比如:空格键)的输入,需要使用PreviewKeyDown来补充处理。
private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Space)
{
//禁止空格键输入,在此处拦截e.Handled = true; 空格输入不会进入PreviewTextInput
e.Handled = true;
}
}
private void TextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
Int16 val;
if (!Int16.TryParse(e.Text,out val))
{
//禁止非数字内容输入,在此处拦截e.Handled = true;
e.Handled = true;
}
}
按键事件可以关联到单个元素上,也可以关联到外层容器上,这样同时对容器内的元素生效的做法效率更高。
焦点
所有元素都可以被焦点选中,原因是Focusable属性是在UIElement类中定义的。
控件类元素Focusable默认为True,非控件类元素Focusable默认为False。
焦点的操作可通过鼠标点击、Tab键、方向键。
Tab键移动顺序通常是从左向右、从上到下。
Tab键移动顺序可以通过属性TabIndex和IsTabStop控制。
不可见或禁用的控件会忽略Tab键焦点顺序。
获取键盘状态
可以检查Shift、Ctrl、Alt等修饰键的状态。
private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
bool a = e.KeyboardDevice.IsKeyToggled(Key.LeftCtrl);
bool b = e.KeyboardDevice.IsKeyDown (Key.LeftCtrl);
bool c = e.KeyboardDevice.IsKeyUp(Key.LeftCtrl);
KeyStates d = e.KeyboardDevice.GetKeyStates(Key.LeftCtrl);
bool f = Keyboard.IsKeyDown(Key.LeftCtrl);
bool g = Keyboard.IsKeyDown(Key.LeftCtrl);
bool h = Keyboard.IsKeyUp(Key.LeftCtrl);
KeyStates i = Keyboard.GetKeyStates(Key.LeftCtrl);
}
鼠标输入
MouseEnter(鼠标指针移动到元素上时引发)
MouseLeave(鼠标指针离开元素上时引发)
MouseEnter和MouseLeave是直接事件。
PreviewMouseMove和MouseMove两个路由事件,当鼠标在元素上移动时引发。
private void Rectangle_MouseMove(object sender, MouseEventArgs e)
{
//返回相对于指定元素的鼠标指针位置。
Point p = e.GetPosition(this);
}
鼠标命中测试的两个属性,源于UIElement类定义
IsMouseOver:确定当前鼠标是否位于某个元素及其子元素上面。注意:这里子元素即时超过父元素的边界依然可以捕捉到。
IsMouseDirectlyOver:检查鼠标是否直接位于某个元素上面。
鼠标点击
鼠标左/右键和滚轮操作的事件
PreviewMouseLeftButtonDown | MouseLeftButtonDown |
PreviewMouseLeftButtonUp | MouseLeftButtonUp |
PreviewMouseRightButtonDown | MouseRightButtonDown |
PreviewMouseRightButtonUp | MouseRightButtonUp |
PreviewMouseWheel | MouseWheel |
MouseButtonEventArgs类继承自MouseEventArgs类
这里面包含有属性MouseButton(获取引发事件的是哪个鼠标键)、ButtonBase(获取鼠标键的按下/释放状态)、ClickCount(鼠标键单击次数,区分单双击)
通常鼠标单击是对Up事件的响应,而不是Down
某些元素拥有更高级的鼠标事件,例如:Control类有PreviewMouseDoubleClick和MouseDoubleClick事件。
与Keyboard静态对象类似,存在Mouse静态对象,可以用来判断鼠标的操作状态信息。
捕获鼠标
场景:鼠标在元素中按下并移动,移动至元素外释放,导致该元素无法接收到鼠标的释放事件。
调用Mouse.Capture()并传递给目标元素以捕获鼠标。
某个元素捕获鼠标后,其他元素就接收不到鼠标事件了。即鼠标被某个元素捕获后,就不能与其他元素进行交互了。
应用场景:拖放改变元素尺寸、拖放等短时间的操作。
Mouse.Capture(ccc,CaptureMode.SubTree);
CaptureMode属性介绍
None:没有鼠标捕获。 鼠标输入转至鼠标下的元素。
Element:鼠标捕获应用于单个元素。 鼠标输入转至已捕获的元素。
SubTree:鼠标捕获应用于元素的子树。 如果鼠标悬停在具有捕获的元素的子级上,则会将鼠标输入发送至该子元素。 否则,会将鼠标输入发送至具有鼠标捕获的元素。
鼠标捕获丢失可以使用元素的LostMouseCapture事件
鼠标拖放
System.Windows.DragDrop类,使任何元素都可以参与拖放操作。
<Window x:Class="Layout布局.拖放"
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:Layout布局"
mc:Ignorable="d"
Title="拖放" Height="200" Width="500">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Width="100" Background="AliceBlue" Text="你好" VerticalAlignment="Center" HorizontalAlignment="Center" x:Name="tb1" MouseDown="tb1_MouseDown"/>
<!--接收拖放的元素要设置AllowDrop=True和Drop方法-->
<TextBlock Grid.Column="1" Width="100" Background="AliceBlue" VerticalAlignment="Center" HorizontalAlignment="Center" x:Name="tb2" AllowDrop="True" Drop="tb2_Drop" DragEnter="tb2_DragEnter"/>
</Grid>
</Window>
//通常在MouseDown或PreviewMouseDown时,进行DoDragDrop()操作
private void tb1_MouseDown(object sender, MouseButtonEventArgs e)
{
var tb = sender as TextBlock;
DragDrop.DoDragDrop(tb,tb.Text,DragDropEffects.Move);
}
//目标元素 Drop放置
private void tb2_Drop(object sender, DragEventArgs e)
{
var tb = sender as TextBlock;
tb.Text = e.Data.GetData(DataFormats.Text).ToString();
}
//检查正在拖动的内容的数据类型
private void tb2_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.Text))
{
e.Effects = DragDropEffects.Copy;
}
else
{
e.Effects = DragDropEffects.None;
}
}
拖放操作的内容应当使用基本数据类型(字符串、数字等)以及实现了ISerializable或IDataObject的对象(可转换成字节流传递并重新构造成对象)。
触控
也有很多像鼠标和键盘输入一样的事件,如TouchDown、TouchUp等,还需要考虑旋转、多点触控、惯性等问题。
这个地方不多说,特殊需要的时候再研究,多数时候用不到。