WPF中鼠標(biāo)/鍵盤(pán)/拖拽事件以及用行為封裝事件詳解
本文主要介紹了WPF中常用的鼠標(biāo)事件、鍵盤(pán)事件以及注意事項(xiàng),同時(shí)使用一個(gè)案例講解了拓展事件。除此之外,本文還講述如何用行為(Behavior)來(lái)封裝事件。
Windows中的事件通過(guò)消息機(jī)制來(lái)完成,也就是Windows系統(tǒng)來(lái)捕獲用戶輸入(如鼠標(biāo)點(diǎn)擊、鍵盤(pán)輸入),然后Windows發(fā)送一個(gè)消息給應(yīng)用程序,應(yīng)用程序進(jìn)行具體的處理。在Winform中,窗體中每個(gè)控件都是有獨(dú)立的句柄,也就是每個(gè)控件都可以收到Windows系統(tǒng)傳來(lái)的消息,但是在WPF中,窗體中的控件是沒(méi)有句柄的,所以只能是窗體進(jìn)行消息捕獲,WPF框架經(jīng)過(guò)處理再傳遞給相應(yīng)的控件。這是WPF和Winform在事件處理上的不同之處。
鼠標(biāo)事件
常用的鼠標(biāo)事件包括:
MouseEnter、MouseLeave、MouseDown、MouseUp、MouseMove、MouseLeftButtonDown、MouseLeftButtonUp、MouseRightButtonDown、MouseRightButtonUp、MouseDoubleClick
值得注意的是諸如Button一類的控件,具有Click事件,它其實(shí)是仍然是調(diào)用了MouseLeftButtonDown等底層事件,然后進(jìn)行截?cái)?,也就是說(shuō)Button控件只能調(diào)用Click事件而不能調(diào)用MouseLeftButtonDown事件,因?yàn)樵贑lick事件中,調(diào)用了MouseLeftButtonDown事件,而且應(yīng)用了e.Handled = true;
阻止事件向下傳下去。如果要在Click事件之前進(jìn)行事件處理,則可以使用PreviewMouseLeftButtonDown
事件。
鍵盤(pán)輸入事件
用的最多的鍵盤(pán)輸入事件有:
KeyDown、KeyUp、TextInput
如果要對(duì)某個(gè)鍵進(jìn)行處理則可以
private void TextBox_KeyDown(object sender, KeyEventArgs e) { if(e.Key == Key.Enter) { //e.Handled = true;//表示已經(jīng)處理完成 //具體邏輯 } }
注意TextBox是不能捕獲到TextInput
事件的,只能捕獲到KeyDown、TextChanged
等事件,但也可以捕獲到PreviewTextInput
事件,事件捕獲順序是KeyDown-PreviewTextInput-TextChanged
。
案例:做一個(gè)搜索欄,輸入文字后回車搜索
實(shí)現(xiàn)方式1:可以在TextBox上增加KeyDown事件,捕獲Key.Enter鍵。
實(shí)現(xiàn)方式2:增加一個(gè)Button按鈕,設(shè)置<Button Content="搜索" IsDefault="True"/>
拖拽事件
拖拽事件包括:Drop、DragLeave、DragOver、DragEnter事件
案例,將某個(gè)控件拖拽到另一個(gè)區(qū)域
界面XAML
<Grid> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <StackPanel x:Name="panel" Background="#F7F9FA"> <Border Background="Orange" Height="30" Width="30" MouseLeftButtonDown="Border_MouseLeftButtonDown"/> </StackPanel> <!--必須設(shè)置Background,否則默認(rèn)為null,null是沒(méi)有背景和Transparent不同--> <!--AllowDrop="True"必須設(shè)置--> <Canvas x:Name="canvas" Grid.Column="1" Drop="Canvas_Drop" AllowDrop="True" Background="Transparent"> </Canvas> </Grid>
實(shí)現(xiàn)代碼
private void Canvas_Drop(object sender, DragEventArgs e) { var data = e.Data.GetData(typeof(Border)); //canvas.Children.Add(data);//直接這樣不可以,因?yàn)橥粋€(gè)實(shí)例不允許在于兩個(gè)容器中 //先在之前的容器中移除,再添加 panel.Children.Remove(data as UIElement); canvas.Children.Add(data as UIElement); //獲得鼠標(biāo)相對(duì)于canvas的位置 var point = e.GetPosition((Canvas)sender); Canvas.SetLeft(data as UIElement, point.X); Canvas.SetTop(data as UIElement, point.Y); } private void Border_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { Border border = sender as Border; DragDrop.DoDragDrop(border, border, DragDropEffects.Copy); }
用行為封裝事件
通過(guò)一個(gè)案例來(lái)講解
案例,實(shí)現(xiàn)某個(gè)控件的隨意拖動(dòng)
用事件來(lái)實(shí)現(xiàn)
主要是通過(guò)MouseLeftButtonDown、MouseLeftButtonUp和MouseMove
三個(gè)事件來(lái)實(shí)現(xiàn)
XAML界面
<Canvas> <Border Background="Orange" Width="100" Height="50" Canvas.Left="100" Canvas.Top="100" MouseLeftButtonDown="Border_MouseLeftButtonDown" MouseLeftButtonUp="Border_MouseLeftButtonUp" MouseMove="Border_MouseMove" /> </Canvas>
實(shí)現(xiàn)代碼
private Canvas _parentCanvas = null; private bool _isDragging = false; private Point _mouseCurrentPoint; private void Border_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { //獲得承載Border的父對(duì)象 if (_parentCanvas == null) _parentCanvas = (Canvas)VisualTreeHelper.GetParent(sender as Border); this._isDragging = true; //獲得相對(duì)于border的坐標(biāo) this._mouseCurrentPoint = e.GetPosition(sender as Border); //關(guān)鍵,鎖定鼠標(biāo)即不讓鼠標(biāo)選中其他元素 (sender as Border).CaptureMouse(); } private void Border_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { if (_isDragging) { //關(guān)鍵,取消鎖定鼠標(biāo) (sender as Border).ReleaseMouseCapture(); _isDragging = false; } } private void Border_MouseMove(object sender, MouseEventArgs e) { if (_isDragging) { //獲得相對(duì)于Canvas的坐標(biāo) Point point = e.GetPosition(_parentCanvas); (sender as Border).SetValue(Canvas.TopProperty, point.Y - _mouseCurrentPoint.Y); (sender as Border).SetValue(Canvas.LeftProperty, point.X - _mouseCurrentPoint.X); } }
關(guān)鍵點(diǎn):
在進(jìn)行移動(dòng)的時(shí)候,一定要鎖定鼠標(biāo),也就是不讓鼠標(biāo)可以選中其他元素,如果不鎖定會(huì)出現(xiàn)以下情況:
情況1:如果鼠標(biāo)移動(dòng)過(guò)快,會(huì)出現(xiàn)圖形不能跟隨的情況
情況2:如果有多個(gè)元素,會(huì)出現(xiàn)選中其他元素的情況
下圖演示中,鼠標(biāo)箭頭未松開(kāi)
鎖定鼠標(biāo)有兩種方式
(sender as Border).CaptureMouse()//鎖定 (sender as Border).ReleaseMouseCapture();//解鎖 System.Windows.Input.Mouse.Capture(sender as Border);//鎖定 System.Windows.Input.Mouse.Capture(null);//解鎖
用行為來(lái)封裝
上文中主要是通過(guò)MouseLeftButtonDown、MouseLeftButtonUp和MouseMove
三個(gè)事件來(lái)實(shí)現(xiàn),在XAML中需要對(duì)這三個(gè)事件進(jìn)行綁定。行為則可以將這三個(gè)事件封裝在一起。
- 使用行為需要nuget安裝
Microsoft.Xaml.Behaviors.Wpf
,F(xiàn)rameWork版本安裝System.Windows.Interactivity.WPF
- 新建一個(gè)類,繼承自
Behavior<T>
,類中重寫(xiě)OnAttached()和OnDetaching()方法。
OnAttached()表示當(dāng)掛載到對(duì)應(yīng)的對(duì)象上的時(shí)候觸發(fā)
OnDetaching()在對(duì)象銷毀時(shí)觸發(fā)
public class DragMoveBehavior : Behavior<Border> { // 當(dāng)掛載到對(duì)應(yīng)的對(duì)象上的時(shí)候觸發(fā) protected override void OnAttached() { base.OnAttached(); //方法與上面相同 //this.AssociatedObject表示關(guān)聯(lián)的對(duì)象 this.AssociatedObject.MouseLeftButtonDown += AssociatedObject_MouseLeftButtonDown; this.AssociatedObject.MouseLeftButtonUp += AssociatedObject_MouseLeftButtonUp; this.AssociatedObject.MouseMove += AssociatedObject_MouseMove; } private Canvas _parentCanvas = null; private bool _isDragging = false; private Point _mouseCurrentPoint; private void AssociatedObject_MouseMove(object sender, System.Windows.Input.MouseEventArgs e) { if (_isDragging) { // 相對(duì)于Canvas的坐標(biāo) Point point = e.GetPosition(_parentCanvas); // 設(shè)置最新坐標(biāo) this.AssociatedObject.SetValue(Canvas.TopProperty, point.Y - _mouseCurrentPoint.Y); this.AssociatedObject.SetValue(Canvas.LeftProperty, point.X - _mouseCurrentPoint.X); } } private void AssociatedObject_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e) { if (_isDragging) { // 釋放鼠標(biāo)鎖定 //this.AssociatedObject.ReleaseMouseCapture(); System.Windows.Input.Mouse.Capture(null); _isDragging = false; } } private void AssociatedObject_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e) { this._isDragging = true; // Canvas if (_parentCanvas == null) _parentCanvas = (Canvas)VisualTreeHelper.GetParent(sender as Border); // 當(dāng)前鼠標(biāo)坐標(biāo) this._mouseCurrentPoint = e.GetPosition(sender as Border); // 鼠標(biāo)鎖定 //this.AssociatedObject.CaptureMouse(); System.Windows.Input.Mouse.Capture(this.AssociatedObject); } // 對(duì)象銷毀 protected override void OnDetaching() { this.AssociatedObject.MouseLeftButtonDown -= AssociatedObject_MouseLeftButtonDown; this.AssociatedObject.MouseLeftButtonUp -= AssociatedObject_MouseLeftButtonUp; this.AssociatedObject.MouseMove -= AssociatedObject_MouseMove; } }
XAML中代碼
<Canvas> <Border Background="Orange" Width="100" Height="50" Canvas.Left="100" Canvas.Top="100"> <i:Interaction.Behaviors> <local:DragMoveBehavior/> </i:Interaction.Behaviors> </Border> </Canvas>
以上就是WPF中鼠標(biāo)/鍵盤(pán)/拖拽事件以及用行為封裝事件詳解的詳細(xì)內(nèi)容,更多關(guān)于WPF事件的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Unity實(shí)現(xiàn)答題系統(tǒng)的示例代碼
這篇文章主要和大家分享了利用Unity制作一個(gè)答題系統(tǒng)的示例代碼,文中的實(shí)現(xiàn)方法講解詳細(xì),對(duì)我們學(xué)習(xí)或工作有一定的幫助,需要的可以參考一下2022-05-05C#使用IronPython庫(kù)調(diào)用Python腳本
這篇文章介紹了C#使用IronPython庫(kù)調(diào)用Python腳本的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06關(guān)于C# TabPage如何隱藏的問(wèn)題
TabPage沒(méi)有Visible屬性,所以只能通過(guò)設(shè)置將其與父控件(tabcontrol)的關(guān)聯(lián)性去除就好了,如下面代碼:2013-04-04C#的正則表達(dá)式Regex類使用簡(jiǎn)明教程
這篇文章主要介紹了C#的正則表達(dá)式Regex類使用簡(jiǎn)明教程,分別講解了如何匹配、如何獲取匹配次數(shù)、如何獲取匹配內(nèi)容及捕獲的方法,需要的朋友可以參考下2014-08-08C#中的數(shù)組作為參數(shù)傳遞所引發(fā)的問(wèn)題
這篇文章主要介紹了C#中的數(shù)組作為參數(shù)傳遞所引發(fā)的問(wèn)題 的相關(guān)資料,需要的朋友可以參考下2016-03-03C# 泛型數(shù)組學(xué)習(xí)小結(jié)
C# 泛型數(shù)組學(xué)習(xí)中我們需要注意什么事項(xiàng)呢?C# 泛型數(shù)組的使用又是如何呢?那么本文就向你詳細(xì)介紹這方面的內(nèi)容2012-09-09