多點觸控輸入
多點觸控輸入和傳統的基於比的輸入的區別是多點觸控識別手勢,使用者可以移動多根手指以執行常見的操作,放大,旋轉,拖動等。
多點觸控的輸入層次
WPF允許使用鍵盤和滑鼠的高層次輸入(例如單擊和文字改變)和低層次輸入(滑鼠事件和按鍵事件)。多點觸控輸入同樣應用了這種多層次的輸入方式,WPF提供了3個獨立的層次:
- 原始觸控(raw touch):這是最低階的支援,可訪問使用者執行的每個觸控。缺點是由應用程式負責將單獨的觸控訊息組合在一起,並對他們進行解釋。如果不準備識別標準觸控手勢,反而希望建立以獨特方式響應多點觸控輸入的應用程式,使用原始觸控是合理的。一個例子就是繪圖程式,允許使用者同時使用多根手指在觸控式螢幕上繪圖。
- 操作(manipulation):這是一個簡便的抽象層,該層將原始的多點觸控輸入轉換成更有意義的手勢,與WPF控制元件將一系列MouseDown和MouseUp事件解釋為更高階的MouseDoubleClick事件相似。WPF支援的通用手勢包括移動Pan,縮放Zoom,旋轉Rotate,輕按Tap
- 內建的元素支援:有些元素已經對多點觸控事件提供了內建的支援,從而不需要在編寫程式碼。例如,可滾動的控制元件支援觸控移動,ListBox、ListView、DataGrid、TextBox、ScrollViewer
原始觸控
觸控事件被內建到了低階的UIElement以及ContentElemnet類。所有元素的原始觸控事件:
名稱 | 路由型別 | 說明 |
---|---|---|
PreviewTouchDown | 隧道 | 當使用者觸控元素時發生 |
TouchDown | 冒泡 | 當使用者觸控元素時發生 |
PreviewTouchMove | 隧道 | 當使用者移動放到觸控式螢幕上的手指時發生 |
TouchMove | 冒泡 | 當使用者移動放到觸控式螢幕上的手指時發生 |
PreviewTouchUp | 隧道 | 當使用者移開手指,結束觸控時發生 |
TouchUp | 冒泡 | 當使用者移開手指,結束觸控時發生 |
TouchEnter | 無 | 當觸點從元素外進入元素內時發生 |
TouchLeave | 無 | 當觸點離開元素時發生 |
所有這些事件都提供了一個TouchEventArgs物件,該物件提供了兩個重要成員。第一個是GetTouchPoint()方法,該方法返回觸控事件發生位置的螢幕座標(還有觸點的大小等)。第二個是TouchDevice屬性,該屬性返回一個TouchDevice物件。這裡的技巧是將每個觸點視為單獨裝置。因此,如果使用者在不同的位置按下兩根手指(同時按下或者先按下一個再按下一個),WPF將他們作為兩個觸控裝置,併為每個觸控裝置指定唯一的ID,當使用者移動這些手指,並且觸控事件發生時,程式碼可以通過TouchDevice.ID屬性區分兩個觸點。
操作
WPF為手勢提供了更高階的支援,稱為觸控操作。通過將元素的IsManipulationEnabled屬性設定為true,使元素接受觸控操作。然後可響應4個操作事件:
ManipulationStarting、ManipulationStarted、ManipulationDelta、ManipulationComplted。
<Window x:Class="Multitouch.Manipulations"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Manipulations" Height="349" Width="607">
<Grid>
<Canvas x:Name="canvas" ManipulationStarting="image_ManipulationStarting" ManipulationDelta="image_ManipulationDelta">
<Image Canvas.Top="10" Canvas.Left="10" Width="200" IsManipulationEnabled="True" Source="koala.jpg">
<Image.RenderTransform>
<MatrixTransform></MatrixTransform>
</Image.RenderTransform>
</Image>
<Image Canvas.Top="30" Canvas.Left="350" Width="200" IsManipulationEnabled="True" Source="penguins.jpg">
<Image.RenderTransform>
<MatrixTransform></MatrixTransform>
</Image.RenderTransform>
</Image>
<Image Canvas.Top="100" Canvas.Left="200" Width="200" IsManipulationEnabled="True" Source="tulips.jpg">
<Image.RenderTransform>
<MatrixTransform></MatrixTransform>
</Image.RenderTransform>
</Image>
</Canvas>
</Grid>
</Window>
public partial class Manipulations : Window
{
public Manipulations()
{
InitializeComponent();
}
private void image_ManipulationStarting(object sender, ManipulationStartingEventArgs e)
{
// Set the container (used for coordinates.)
e.ManipulationContainer = canvas;
// Choose what manipulations to allow.
e.Mode = ManipulationModes.All;
}
private void image_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
{
// Get the image that's being manipulated.
FrameworkElement element = (FrameworkElement)e.Source;
// Use the matrix to manipulate the element.
Matrix matrix = ((MatrixTransform)element.RenderTransform).Matrix;
var deltaManipulation = e.DeltaManipulation;
// Find the old center, and apply the old manipulations.
Point center = new Point(element.ActualWidth / 2, element.ActualHeight / 2);
center = matrix.Transform(center);
// Apply zoom manipulations.
matrix.ScaleAt(deltaManipulation.Scale.X, deltaManipulation.Scale.Y, center.X, center.Y);
// Apply rotation manipulations.
matrix.RotateAt(e.DeltaManipulation.Rotation, center.X, center.Y);
// Apply panning.
matrix.Translate(e.DeltaManipulation.Translation.X, e.DeltaManipulation.Translation.Y);
// Set the final matrix.
((MatrixTransform)element.RenderTransform).Matrix = matrix;
}
}
上面每個影像都包含一個MatrixTransform物件,該物件為程式碼應用移動、旋轉、縮放等操作的組合提供了一個簡易方式。當操作發生時,將使用程式碼改變他們。
當觸控一幅圖時,將觸發ManipulationStarting事件。這時,設定操作容器(後面將獲得所有操作座標的參考點)。當操作發生時,觸發ManipulationDelta事件,例如使用者開始旋轉一幅影像,將不斷觸發這個事件,直到使用者旋轉停止或者抬起手指為止。
通過使用ManipulationDelta物件將手勢的當前狀態記錄下來,該物件是通過ManipulationDeltaEventArgs.DeltaManipulation屬性提供的。本質上,ManipulationDelta物件記錄了應該應用到物件的縮放、旋轉、移動的量,分別有3個簡單的屬性提供,Scale、Rotation、Translation,通過這3個資料來調整使用者介面的元素。
慣性
本質上,通過慣性可以更逼真的更流暢的操作元素。如上例中,當手指從觸控式螢幕抬起時影像會立即停止一定。但如果啟用了慣性特性,那麼影像會繼續移動非常短的一段時間,正常地減速。將元素拖動進他們不能穿過的邊界時,慣性還會使元素彈回來。
新增慣性特性,只需處理ManipulationInertiaStarting事件。該事件從一幅影像開始並冒泡到Canvas皮膚。當使用者結束手勢並抬起手指釋放元素時,觸發該事件。可使用ManipulationInertiaStartingEventArgs物件確定當前速度,並設定希望的減速度。