Windows 7 引入了原生多點觸控支援,讓使用者能直接以手指操作應用程式,無需滑鼠或觸控筆等中介裝置。這項技術擴展了平板電腦原有的觸控筆功能,並支援多個觸控點同時輸入,實現十指同步操作甚至多使用者協作等複雜場景。然而,要充分發揮多點觸控優勢,開發者必須調整應用程式的使用者介面與行為,以適應全新的輸入模式。
本實驗將引導您將一個基於滑鼠的簡單圖片操作應用程式,逐步升級為支援多點觸控的現代化應用,體驗類似 Microsoft Surface 的互動效果。
圖 1:啟用了多點觸控的應用程式
為方便實驗,我們以 Visual Studio 程式碼片段形式提供所需程式碼。請先執行實驗 Setup 資料夾下的 MultiTouchLab.vsi 安裝程式碼片段。
要掌握多點觸控輸入處理,首先需理解單點滑鼠輸入的處理方式。我們準備了一個基於滑鼠的圖片處理應用程式作為起點。
%TrainingKitInstallDir%\MultiTouch\Ex1-PictureHandling\Begin 的初始解決方案,選擇 C# 或 VB.NET 版本。應用程式以 Picture 使用者控制項代表每張圖片,基於 WPF 建立。其 XAML 定義如下:
<UserControl x:Class="MultitouchHOL.Picture"
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml">
<Image Source="{Binding Path=ImagePath}" Stretch="Fill" Width="Auto"
Height="Auto" RenderTransformOrigin="0.5, 0.5">
<Image.RenderTransform>
<TransformGroup>
<RotateTransform Angle="{Binding Path=Angle}"></RotateTransform>
<ScaleTransform ScaleX="{Binding Path=ScaleX}" ScaleY="{Binding Path=ScaleY}">
</ScaleTransform>
<TranslateTransform X="{Binding Path=X}" Y="{Binding Path=Y}"/>
</TransformGroup>
</Image.RenderTransform>
</Image>
</UserControl>
該控制項的程式碼僅包含 ImagePath、Angle、ScaleX、ScaleY、X、Y 等相依屬性宣告,分別對應圖片路徑、旋轉角度、縮放比例與中心座標。
主視窗 XAML 僅包含一個 Canvas 面板(名為 _canvas),作為承載 Picture 控制項的容器:
<Window x:Class="MultitouchHOL.MainWindow"
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
Title="MultitouchHOL" Height="300" Width="300" WindowState="Maximized"
xmlns:mt="clr-namespace:MultitouchHOL">
<Canvas Name="_canvas"></Canvas>
</Window>
MainWindow 類別透過 _picture 成員追蹤目前被拖曳的圖片,_prevLocation 記錄上一次滑鼠位置以計算位移。建構函式註冊滑鼠事件:
public MainWindow()
{
InitializeComponent();
this.Loaded += (s, e) => { LoadPictures(); };
MouseLeftButtonDown += ProcessDown;
MouseMove += ProcessMove;
MouseLeftButtonUp += ProcessUp;
MouseWheel += ProcessMouseWheel;
}
LoadPictures() 從使用者圖片資料夾載入圖片並建立對應的 Picture 控制項。
FindPicture() 進行視覺樹點擊測試找到最上層圖片,並透過 BringPictureToFront() 將其置於最上層。_prevLocation。ScaleX、ScaleY。雖然 WPF 3.5 不原生支援多點觸控(WPF 4.0 才內建),但可透過 Windows 7 Integration Library 範例在當前版本中實現。該程式庫示範如何在 .NET 程式碼中呼叫 Win32 原生 API。
Windows7.Multitouch.dll 與 Windows7.Multitouch.WPF.dll 參考。MainWindow 建構函式中加入檢測程式碼:if (!Windows7.Multitouch.TouchHandler.DigitizerCapabilities.IsMultiTouchReady)
{
MessageBox.Show("Multitouch is not available");
Environment.Exit(1);
}
您還可檢視 TouchHandler.DigitizerCapabilities 的其他屬性以獲取更多硬體資訊。
圖 2:查看 TouchHandler.DigitizerCapabilities 屬性
為啟用手指觸控操作,需移除滑鼠事件註冊,改用觸控筆事件。
using Windows7.Multitouch; using Windows7.Multitouch.WPF;Loaded 事件中呼叫 Factory.EnableStylusEvents(this),指示系統以觸控筆事件形式發送觸控事件。ProcessMouseWheel 及其註冊(縮放功能稍後實作)。StylusEventArgs:public void ProcessDown(object sender, StylusEventArgs args)
{
_prevLocation = args.GetPosition(_canvas);
_picture = FindPicture(_prevLocation);
BringPictureToFront(_picture);
}
public void ProcessMove(object sender, StylusEventArgs args)
{
if (_picture == null) return;
Point newLocation = args.GetPosition(_canvas);
_picture.X += newLocation.X - _prevLocation.X;
_picture.Y += newLocation.Y - _prevLocation.Y;
_prevLocation = newLocation;
}
public void ProcessUp(object sender, StylusEventArgs args)
{
_picture = null;
}
StylusDown += ProcessDown; StylusUp += ProcessUp; StylusMove += ProcessMove;思考:若嘗試使用多根手指會發生什麼情況?為什麼?
每根觸控螢幕的手指都會獲得唯一的觸控 ID,只要手指持續接觸,系統就會保持該 ID 關聯。我們需將觸控 ID 與對應圖片建立連結,實現多指同時操作不同圖片。
透過 args.StylusDevice.Id 可從觸控筆事件參數中取得觸控 ID。WPF 會為每根手指持續觸發帶有相同 ID 的事件。
為同時追蹤多張圖片,我們引入兩個類別:
ProcessDown、ProcessMove、ProcessUp 方法。PictureTracker 的對應字典,負責分派觸控事件給正確的追蹤器。此方法處理三種觸控按下情境:
PictureTracker 並加入字典。PictureTracker。移動與抬起事件則根據觸控 ID 在字典中查找對應追蹤器並轉發處理,最後一個關聯觸控 ID 釋放時移除追蹤器。
class PictureTrackerManager
{
private readonly Dictionary<int, PictureTracker> _pictureTrackerMap = new Dictionary<int, PictureTracker>();
private readonly Canvas _canvas;
public PictureTrackerManager(Canvas canvas) { _canvas = canvas; }
public void ProcessDown(object sender, StylusEventArgs args) { ... }
public void ProcessUp(object sender, StylusEventArgs args) { ... }
public void ProcessMove(object sender, StylusEventArgs args) { ... }
private PictureTracker GetPictureTracker(int touchId) { ... }
private PictureTracker GetPictureTracker(int touchId, Point location) { ... }
private Picture FindPicture(Point location) { ... }
private void BringPictureToFront(Picture picture) { ... }
}
此架構確保每根手指獨立控制對應圖片,實現真正的多點觸控體驗。