(代碼片段 – MultiTouch – PictureTrackerManagerClass VB)
Visual Basic
Imports System.Windows
Imports System.Windows.Controls
Class PictureTrackerManager
' Map between touch ids and picture trackers
Private ReadOnly _pictureTrackerMap As New Dictionary (Of Integer, PictureTracker)
Private ReadOnly _canvas As Canvas
Public Sub New(ByVal canvas As Canvas)
_canvas = canvas
End Sub
Public Sub ProcessDown(ByVal sender As Object, ByVal args As StylusEventArgs)
Dim location = args.GetPosition(_canvas)
Dim pictureTracker = GetPictureTracker (args.StylusDevice.Id, location)
If pictureTracker Is Nothing Then Return
pictureTracker.ProcessDown(location)
End Sub
Public Sub ProcessUp(ByVal sender As Object, ByVal args As StylusEventArgs)
Dim location = args.GetPosition(_canvas)
Dim pictureTracker = GetPictureTracker (args.StylusDevice.Id)
If pictureTracker Is Nothing Then Return
pictureTracker.ProcessUp(location)
_pictureTrackerMap.Remove(args.StylusDevice.Id)
End Sub
Public Sub ProcessMove(ByVal sender As Object, ByVal args As StylusEventArgs)
Dim pictureTracker = GetPictureTracker (args.StylusDevice.Id)
If pictureTracker Is Nothing Then Return
Dim location = args.GetPosition(_canvas)
pictureTracker.ProcessMove(location)
End Sub
Private Function GetPictureTracker(ByVal touchId As Integer) As PictureTracker
Dim pictureTracker As PictureTracker = Nothing
_pictureTrackerMap.TryGetValue(touchId, pictureTracker)
Return pictureTracker
End Function
Private Function GetPictureTracker(ByVal touchId As Integer, ByVal location As Point) As PictureTracker
Dim pictureTracker As PictureTracker = Nothing
' See if we already track the picture with the touchId
If _pictureTrackerMap.TryGetValue(touchId, pictureTracker) Then Return pictureTracker
' Get the picture under the touch location
Dim picture = FindPicture(location)
If picture Is Nothing Then Return Nothing
' See if we track the picture with other ID
pictureTracker = (From entry In _pictureTrackerMap _
Where entry.Value.Picture Is picture _
Select entry.Value).FirstOrDefault()
' First time
If pictureTracker Is Nothing Then
' Create new
pictureTracker = New PictureTracker()
pictureTracker.Picture = picture
BringPictureToFront(picture)
End If
' Remember the corelation between the touch id and the picture
_pictureTrackerMap(touchId) = pictureTracker
Return pictureTracker
End Function
''' <summary>
''' Find the picture in the touch location
''' </summary>
''' <param name="pointF">touch location</param>
''' <returns>The picture or null if no picture exists in the touch
''' location</returns>
Private Function FindPicture(ByVal location As Point) As Picture
Dim result = VisualTreeHelper.HitTest(_canvas, location)
If result Is Nothing Then Return Nothing
Dim image = TryCast(result.VisualHit, Image)
If image Is Nothing Then Return Nothing
Return TryCast(image.Parent, Picture)
End Function
Private Sub BringPictureToFront(ByVal picture As Picture)
If picture Is Nothing Then Return
Dim children = (From child In _canvas.Children _
Where child IsNot picture _
Order By Canvas.GetZIndex(child) _
Select child).ToArray()
For i = 0 To children.Length - 1
Canvas.SetZIndex(children(i), i)
Next i
Canvas.SetZIndex(picture, children.Length)
End Sub
End Class
5.將以下字段聲明添加到 MainWindow 類的開頭:
C#
private readonly PictureTrackerManager _pictureTrackerManager;
Visual Basic
Private ReadOnly _pictureTrackerManager As PictureTrackerManager
6.修改 MainWindow 構造函數:
a.在調用 InitializeComponent() 之後,添加管理器初始化:
C#
_pictureTrackerManager = new PictureTrackerManager(_canvas);
Visual Basic
_pictureTrackerManager = New PictureTrackerManager(_canvas)
b.更改觸筆事件注冊代碼
(代碼片段 – MultiTouch – PictureTrackerManagerEventHandlers CSharp)
C#
//Register for stylus (touch) events
StylusDown += _pictureTrackerManager.ProcessDown;
StylusUp += _pictureTrackerManager.ProcessUp;
StylusMove += _pictureTrackerManager.ProcessMove;
(代碼片段 – MultiTouch – PictureTrackerManagerEventHandlers VB)
Visual Basic
' Register for stylus (touch) events
AddHandler Me.StylusDown, AddressOf _pictureTrackerManager.ProcessDown
AddHandler Me.StylusMove, AddressOf _pictureTrackerManager.ProcessMove
AddHandler Me.StylusUp, AddressOf _pictureTrackerManager.ProcessUp
7.從 MainWindow 類刪除 ProcessDown、ProcessMove 和 ProcessUp 事件處 理程序。這裡將不再需要它們,因為它們現在已包含在 PictureTrackerManager 類中。
8.編譯並運行。嘗試同時抓取多張圖片。嘗試使用多個手指抓取一張圖片。發 生了什麼情況?為什麼?
任務 5 – 使用多點觸摸操作處理圖片
到目前為止,使用觸摸事件處理圖片與使用鼠標功能並沒有太大區別。在 本任務中,我們將:
• 添加使用多 個手指操作圖片的能力
• 同時平移 、縮放和旋轉圖片
• 同時操作多張 圖片
我們已經知道如何將正確的事件分派給相應的 PictureTracker,但 我們還不知道如何決定在發生多個事件之後需要采取的操作。這正是 Windows 7 多點觸摸機制的用武之地。它擁有一個操作處理器來使用觸摸 ID 事件並生成合 適的操作事件。您只需實例化一個操作處理器,注冊其事件,並為它提供觸摸 ID + 位置事件對。
操作處理器是一個 COM 對象。要在 .NET 中使用它,可以使用 Windows 7 Integration Library 示例。ManipulationProcessor .NET 包裝器類構造函數獲 得一個枚舉值,該值告訴它要報告哪些操作。在我們的示例中,我們希望報告所 有操作。該處理器有 3 個事件:ManipulationStarted、ManipulationCompleted 和 ManipulationDelta。ManipulationDelta 是我們所關注的事件。它提供了平 移、旋轉和縮放的偏移量。
1.更改整個 PictureTracker 類。
( 代碼片段 – MultiTouch – PictureTrackerManipulationProcessorClass CSharp)
C#
class PictureTracker
{
private readonly ManipulationProcessor _processor =
new ManipulationProcessor(ProcessorManipulations.ALL);
public PictureTracker()
{
_processor.ManipulationStarted += (s, e) =>
{
System.Diagnostics.Trace.WriteLine ("Manipulation has started: " + Picture.ImagePath);
};
_processor.ManipulationCompleted += (s, e) =>
{
System.Diagnostics.Trace.WriteLine("Manipulation has completed: " + Picture.ImagePath);
};
_processor.ManipulationDelta += ProcessManipulationDelta;
}
public Picture Picture { get; set; }
public void ProcessDown(int id, Point location)
{
_processor.ProcessDown((uint)id, location.ToDrawingPointF());
}
public void ProcessMove(int id, Point location)
{
_processor.ProcessMove((uint)id, location.ToDrawingPointF());
}
public void ProcessUp(int id, Point location)
{
_processor.ProcessUp ((uint)id, location.ToDrawingPointF());
}
//Update picture state
private void ProcessManipulationDelta(object sender, ManipulationDeltaEventArgs e)
{
if (Picture == null)
return;
Picture.X += e.TranslationDelta.Width;
Picture.Y += e.TranslationDelta.Height;
Picture.Angle += e.RotationDelta * 180 / Math.PI;
Picture.ScaleX *= e.ScaleDelta;
Picture.ScaleY *= e.ScaleDelta;
}
}
(代碼片段 – MultiTouch – PictureTrackerManipulationProcessorClass VB)
Visual Basic
Class PictureTracker
Private _picture As Picture
Public Property Picture() As Picture
Get
Return _picture
End Get
Set(ByVal value As Picture)
_picture = value
End Set
End Property
Private WithEvents _processor As New ManipulationProcessor(ProcessorManipulations.ALL)
Public Sub New()
End Sub
Private Sub Processor_OnManipulationStarted() Handles _processor.ManipulationStarted
System.Diagnostics.Trace.WriteLine("Manipulation has started: " & Picture.ImagePath)
End Sub
Private Sub Processor_OnManipulationCompleted() Handles _processor.ManipulationCompleted
System.Diagnostics.Trace.WriteLine("Manipulation has completed: " & Picture.ImagePath)
End Sub
' Update picture state
Private Sub ProcessManipulationDelta(ByVal sender As Object, ByVal e As ManipulationDeltaEventArgs) Handles _processor.ManipulationDelta
If Picture Is Nothing Then Return
Picture.X += e.TranslationDelta.Width
Picture.Y += e.TranslationDelta.Height
Picture.Angle += e.RotationDelta * 180 / Math.PI
Picture.ScaleX *= e.ScaleDelta
Picture.ScaleY *= e.ScaleDelta
End Sub
Public Sub ProcessDown(ByVal id As Integer, ByVal location As Point)
_processor.ProcessDown(CUInt(id), location.ToDrawingPointF())
End Sub
Public Sub ProcessMove(ByVal id As Integer, ByVal location As Point)
_processor.ProcessMove(CUInt(id), location.ToDrawingPointF())
End Sub
Public Sub ProcessUp(ByVal id As Integer, ByVal location As Point)
_processor.ProcessUp(CUInt(id), location.ToDrawingPointF())
End Sub
End Class
2.將以下命名空間指令添加到 PictureTracker 類中:
C#
using Windows7.Multitouch.Manipulation;
using Windows7.Multitouch.WPF;
Visual Basic
Imports Windows7.Multitouch.Manipulation
Imports Windows7.Multitouch.WPF
注意: 通過添加此命名空間,可以使用 ManipulatorProcessor 類和 System.Windows.Point 擴展方法 ToDrawingPointF。
3.我們實例化了一個新的 ManipulationProcessor,注冊了事件處理器,而且 最重要的是,通過更新圖片用戶控件處理了 ManipulationDelta 事件。現在我們 需要對 PictureTrackerManager 事件處理代碼稍作修改,並轉發觸摸 ID 和觸摸 位置。ManipulationProcessor 需要將觸摸 ID 作為操作流程的輸入。更改 PictureTrackerManager 中的以下代碼:
C#
public void ProcessDown(object sender, StylusEventArgs args)
{
Point location = args.GetPosition(_canvas);
PictureTracker pictureTracker = GetPictureTracker (args.StylusDevice.Id, location);
if (pictureTracker == null)
return;
pictureTracker.ProcessDown(args.StylusDevice.Id, location);
}
public void ProcessUp(object sender, StylusEventArgs args)
{
Point location = args.GetPosition(_canvas);
PictureTracker pictureTracker = GetPictureTracker (args.StylusDevice.Id);
if (pictureTracker == null)
return;
pictureTracker.ProcessUp(args.StylusDevice.Id, location);
_pictureTrackerMap.Remove(args.StylusDevice.Id);
}
public void ProcessMove(object sender, StylusEventArgs args)
{
PictureTracker pictureTracker = GetPictureTracker (args.StylusDevice.Id);
if (pictureTracker == null)
return;
Point location = args.GetPosition(_canvas);
pictureTracker.ProcessMove(args.StylusDevice.Id, location);
}
Visual Basic
Public Sub ProcessDown(ByVal sender As Object, ByVal args As StylusEventArgs)
Dim location = args.GetPosition(_canvas)
Dim pictureTracker = GetPictureTracker (args.StylusDevice.Id, location)
If pictureTracker Is Nothing Then Return
pictureTracker.ProcessDown(args.StylusDevice.Id, location)
End Sub
Public Sub ProcessUp(ByVal sender As Object, ByVal args As StylusEventArgs)
Dim location = args.GetPosition(_canvas)
Dim pictureTracker = GetPictureTracker (args.StylusDevice.Id)
If pictureTracker Is Nothing Then Return
pictureTracker.ProcessUp(args.StylusDevice.Id, location)
_pictureTrackerMap.Remove(args.StylusDevice.Id)
End Sub
Public Sub ProcessMove(ByVal sender As Object, ByVal args As StylusEventArgs)
Dim pictureTracker = GetPictureTracker (args.StylusDevice.Id)
If pictureTracker Is Nothing Then Return
Dim location = args.GetPosition(_canvas)
pictureTracker.ProcessMove(args.StylusDevice.Id, location)
End Sub
4.編譯並運行代碼。嘗試同時操作多張圖片。
任務 6 – 添加 PictureTracker 緩存
當用戶首次觸摸一張圖片時,應用程序創建一個新 PictureTracker 實例,該 實例然後創建 ManipulationProcessor COM 對象。只要用戶移開觸摸該圖片的最 後一個指頭(觸摸 ID),PictureTracker 實例就會被當作垃圾收集,進而釋放 底層 COM 對象。分析常見的應用程序使用情形就會發現,只有少數圖片可能被同 時操作。據此可以得出結論:我們需要 PictureTracker 實例的一個緩存。該緩 存將包含空閒的 PictureTracker 實例。當(發生 ProcessDown 事件時)需要新 PictureTracker 實例時,我們將首先嘗試從緩存拉取實例,只有當緩存為空時才 生成新實例。當完成對圖片的操作時,我們將 PictureTracker 實例移入緩存。 因為 ManipulationCompleted 是一個 ManipulationProcessor 事件,所以我們 將要求 PictureTracker 處理該事件並將其轉發給 PictureTrackerManager。這 需要一個從 PictureTracker 到它的 PictureTrackerManager 的新引用(我們使 用構造函數來傳遞該引用)。
1.將堆棧數據成員添加到 PictureTrackerManager 類的開頭:
C#
class PictureTrackerManager
{
//Cache for re-use of picture trackers
private readonly Stack<PictureTracker> _pictureTrackers = new Stack<PictureTracker>();
...
Visual Basic
Class PictureTrackerManager
' Cache for re-use of picture trackers
Private ReadOnly _pictureTrackers As New Stack(Of PictureTracker)()
...
2.更改 GetPictureTracker() 函數。我們需要使用緩存,還需要將此引用傳 遞給 PictureTracker 構造函數:
C#
private PictureTracker GetPictureTracker(int touchId, Point location)
{
...
//First time
if (pictureTracker == null)
{
//take from stack
if (_pictureTrackers.Count > 0)
pictureTracker = _pictureTrackers.Pop ();
else //create new
pictureTracker = new PictureTracker (this);
pictureTracker.Picture = picture;
BringPictureToFront(picture);
}
...
}
Visual Basic
Private Function GetPictureTracker(ByVal touchId As Integer, ByVal location As Point) As PictureTracker
...
' First time
If pictureTracker Is Nothing Then
' take from stack
If _pictureTrackers.Count > 0 Then
pictureTracker = _pictureTrackers.Pop()
Else ' create new
pictureTracker = New PictureTracker(Me)
End If
pictureTracker.Picture = picture
BringPictureToFront(picture)
End If
...
End Function
3.添加一個邏輯,以在操作完成時將 PictureTracker 實例推回堆棧中。將以 下代碼粘貼到 PictureTrackerManager 類中。
C#
//Manipulation is completed, we can reuse the object
public void Completed(PictureTracker pictureTracker)
{
pictureTracker.Picture = null;
_pictureTrackers.Push(pictureTracker);
}
Visual Basic
' Manipulation is completed, we can reuse the object
Public Sub Completed(ByVal pictureTracker As PictureTracker)
pictureTracker.Picture = Nothing
_pictureTrackers.Push(pictureTracker)
End Sub
4.現在需要更改 PictureTracker 類,使其適應 PictureTrackerManager 中 的代碼更改。
a.將 PictureTrackerManager 實例獲取到構造函數中,然後存儲它。
C#
class PictureTracker
{
private readonly ManipulationProcessor _processor =
new ManipulationProcessor (ProcessorManipulations.ALL);
private readonly PictureTrackerManager _pictureTrackerManager;
public PictureTracker(PictureTrackerManager pictureTrackerManager)
{
_pictureTrackerManager = pictureTrackerManager;
...
Visual Basic
Class PictureTracker
...
Private ReadOnly _pictureTrackerManager As PictureTrackerManager
Private WithEvents _processor As New ManipulationProcessor(ProcessorManipulations.ALL)
Public Sub New(ByVal pictureTrackerManager As PictureTrackerManager)
_pictureTrackerManager = pictureTrackerManager
End Sub
...
b.在 ManipulationCompleted 事件中調用 PictureTrackerManager.Completed 函數:
C#
public PictureTracker(PictureTrackerManager pictureTrackerManager)
{
_pictureTrackerManager = pictureTrackerManager;
_processor.ManipulationCompleted += (s, e) =>
{
System.Diagnostics.Trace.WriteLine("Manipulation has completed: " + Picture.ImagePath);
_pictureTrackerManager.Completed(this);
};
...
Visual Basic
Private Sub Processor_OnManipulationCompleted() Handles _processor.ManipulationCompleted
System.Diagnostics.Trace.WriteLine("Manipulation has completed: " & Picture.ImagePath)
_pictureTrackerManager.Completed(Me)
End Sub
5.編譯並運行!
任務 7 – 添加慣性
只剩最後一項任務了。使用縮放、平移和旋轉操作可以提供一種自然的用戶體 驗。在實際生活中,當推動一個物體,然後松開手時,該物體會繼續移動,直到 因為無法克服摩擦力而停止。可以使用 Inertia 讓我們的圖片對象擁有相同的行 為。Windows 7 多點觸摸子系統提供了一個 InertiaProcessor COM 對象。 InertiaProcessor 可以發起與 ManipulationProcessor 相同的操作事件。 Windows 7 Integration Library 示例提供了一個包裝器,它將操作處理器和慣 性處理器捆綁在一起。ManipulationInertiaProcessor 可以替代 ManipulationProcessor 並提供額外的 InertiaProcessor 屬性來公開 InertiaProcessor 功能。要發起更多事件,ManipulationInertiaProcessor 需 要一個計時器。為了克服線程的 UI 相似性問題,我們最好擁有一個基於 GUI 的 計時器。Windows 7 Integration Library 可以為我們創建這樣的計時器。
當用戶的最後一個手指離開圖片對象時,ManipulationInertiaProcessor 會 發起 OnBeforeInertia 事件。在這裡設置 Inertia 開始參數。可以選擇一個默 認的開始速度,或者跟蹤當前的對象速度並從中提取出速度數字。
1.我們想要跟蹤對象的平移、旋轉和縮放速度。將以下類添加到 PictureTracker 類中:
(代碼片段 – MultiTouch – InertiaParamClass CSharp)
C#
//Keep track of object velocities
private class InertiaParam
{
public VectorF InitialVelocity { get; set; }
public float InitialAngularVelocity { get; set; }
public float InitialExpansionVelocity { get; set; }
public System.Diagnostics.Stopwatch _stopwatch = new System.Diagnostics.Stopwatch();
public void Reset()
{
InitialVelocity = new VectorF(0, 0);
InitialAngularVelocity = 0;
InitialExpansionVelocity = 0;
_stopwatch.Reset();
_stopwatch.Start();
}
public void Stop()
{
_stopwatch.Stop();
}
//update velocities, velocity = distance/time
public void Update(ManipulationDeltaEventArgs e, float history)
{
float elappsedMS = (float) _stopwatch.ElapsedMilliseconds;
if (elappsedMS == 0)
elappsedMS = 1;
InitialVelocity = InitialVelocity * history + ((VectorF)e.TranslationDelta * (1F - history)) / elappsedMS;
InitialAngularVelocity = InitialAngularVelocity * history + (e.RotationDelta * (1F - history)) / elappsedMS;
InitialExpansionVelocity = InitialExpansionVelocity * history + (e.ExpansionDelta * (1F - history)) / elappsedMS;
_stopwatch.Reset();
_stopwatch.Start();
}
}
(代碼片段 – MultiTouch – InertiaParamClass VB)
Visual Basic
' Keep track of object velocities.
Private Class InertiaParam
Private _initialVelocity As VectorF
Public Property InitialVelocity() As VectorF
Get
Return _initialVelocity
End Get
Set(ByVal value As VectorF)
_initialVelocity = value
End Set
End Property
Private _initialAngularVelocity As Single
Public Property InitialAngularVelocity() As Single
Get
Return _initialAngularVelocity
End Get
Set(ByVal value As Single)
_initialAngularVelocity = value
End Set
End Property
Private _initialExpansionVelocity As Single
Public Property InitialExpansionVelocity() As Single
Get
Return _initialExpansionVelocity
End Get
Set(ByVal value As Single)
_initialExpansionVelocity = value
End Set
End Property
Public _stopwatch As New System.Diagnostics.Stopwatch()
Public Sub Reset()
InitialVelocity = New VectorF(0, 0)
InitialAngularVelocity = 0
InitialExpansionVelocity = 0
_stopwatch.Reset()
_stopwatch.Start()
End Sub
Public Sub [Stop]()
_stopwatch.Stop()
End Sub
'update velocities, velocity = distance/time
Public Sub Update(ByVal e As ManipulationDeltaEventArgs, ByVal history As Single)
Dim elappsedMS = CSng (_stopwatch.ElapsedMilliseconds)
If elappsedMS = 0 Then elappsedMS = 1
InitialVelocity = InitialVelocity * history + (CType(e.TranslationDelta, VectorF) * (1.0F - history)) / elappsedMs
InitialAngularVelocity = InitialAngularVelocity * history + (e.RotationDelta * (1.0F - history)) / elappsedMs
InitialExpansionVelocity = InitialExpansionVelocity * history + (e.ExpansionDelta * (1.0F - history)) / elappsedMs
_stopwatch.Reset()
_stopwatch.Start()
End Sub
End Class
2.將 OnBeforeInertia() 事件處理程序添加到 PictureTracker 類中:
(代碼片段 – MultiTouch – OnBeforeInertia CSharp)
C#
//Fingers removed, start inertia
void OnBeforeInertia(object sender, BeforeInertiaEventArgs e)
{
//Tell the tracker manager that the user removed the fingers
_pictureTrackerManager.InInertia(this);
_processor.InertiaProcessor.InertiaTimerInterval = 15;
_processor.InertiaProcessor.MaxInertiaSteps = 500;
_processor.InertiaProcessor.InitialVelocity = _inertiaParam.InitialVelocity;
_processor.InertiaProcessor.DesiredDisplacement = _inertiaParam.InitialVelocity.Magnitude * 250;
_processor.InertiaProcessor.InitialAngularVelocity = _inertiaParam.InitialAngularVelocity * 20F / (float)Math.PI;
_processor.InertiaProcessor.DesiredRotation = Math.Abs (_inertiaParam.InitialAngularVelocity *
_processor.InertiaProcessor.InertiaTimerInterval * 540F / (float)Math.PI);
_processor.InertiaProcessor.InitialExpansionVelocity = _inertiaParam.InitialExpansionVelocity * 15;
_processor.InertiaProcessor.DesiredExpansion = Math.Abs (_inertiaParam.InitialExpansionVelocity * 4F);
}
(代碼片段 – MultiTouch – OnBeforeInertia VB)
Visual Basic
' Fingers removed, start inertia
Private Sub OnBeforeInertia(ByVal sender As Object, ByVal e As BeforeInertiaEventArgs)
'Tell the tracker manager that the user removed the fingers
_pictureTrackerManager.InInertia(Me)
_processor.InertiaProcessor.InertiaTimerInterval = 15
_processor.InertiaProcessor.MaxInertiaSteps = 500
_processor.InertiaProcessor.InitialVelocity = _inertiaParam.InitialVelocity
_processor.InertiaProcessor.DesiredDisplacement = _inertiaParam.InitialVelocity.Magnitude * 250
_processor.InertiaProcessor.InitialAngularVelocity = _inertiaParam.InitialAngularVelocity * 20.0F / CSng(Math.PI)
_processor.InertiaProcessor.DesiredRotation = Math.Abs (_inertiaParam.InitialAngularVelocity * _processor.InertiaProcessor.InertiaTimerInterval * 540.0F / CSng (Math.PI))
_processor.InertiaProcessor.InitialExpansionVelocity = _inertiaParam.InitialExpansionVelocity * 15
_processor.InertiaProcessor.DesiredExpansion = Math.Abs (_inertiaParam.InitialExpansionVelocity * 4.0F)
End Sub
3.更改 PictureTracker 類,創建 ManipulationInertiaProcessor 並注冊 OnBeforeInertia 事件:
C#
/// <summary>
/// Track a single picture
/// </summary>
class PictureTracker
{
...
//Calculate the Inertia start velocity
private readonly InertiaParam _inertiaParam = new InertiaParam();
private readonly ManipulationInertiaProcessor _processor = new ManipulationInertiaProcessor(ProcessorManipulations.ALL, Factory.CreateTimer());
public PictureTracker(PictureTrackerManager pictureTrackerManager)
{
_pictureTrackerManager = pictureTrackerManager;
//Start inertia velocity calculations
_processor.ManipulationStarted += (s, e) =>
{
_inertiaParam.Reset();
};
//All completed, inform the tracker manager that the current tracker
//can be reused
_processor.ManipulationCompleted += (s, e) =>
{
_inertiaParam.Stop();
pictureTrackerManager.Completed(this);
};
_processor.ManipulationDelta += ProcessManipulationDelta;
_processor.BeforeInertia += OnBeforeInertia;
}
...
Visual Basic
Class PictureTracker
...
Private ReadOnly _pictureTrackerManager As PictureTrackerManager
'Calculate the Inertia start velocity
Private ReadOnly _inertiaParam As New InertiaParam()
Private WithEvents _processor As New ManipulationInertiaProcessor(ProcessorManipulations.ALL, Factory.CreateTimer())
Public Sub New(ByVal pictureTrackerManager As PictureTrackerManager)
_pictureTrackerManager = pictureTrackerManager
End Sub
Private Sub Processor_OnManipulationStarted() Handles _processor.ManipulationStarted
_inertiaParam.Reset()
End Sub
Private Sub Processor_OnManipulationCompleted() Handles _processor.ManipulationCompleted
_inertiaParam.Stop()
_pictureTrackerManager.Completed(Me)
End Sub
...
Private Sub OnBeforeInertia(ByVal sender As Object, ByVal e As BeforeInertiaEventArgs) Handles _processor.BeforeInertia
...
End Sub
...
4.我們還需要更改 PictureTrackerManager。在新的條件下,圖片可能由慣性 處理器使用,即使沒有手指在觸摸該對象。我們需要在操作完成時立即從映射中 刪除觸摸 ID,但是只有在慣性處理器使圖片完全停止時,我們才能夠重用 PictureTracker 對象。將 InInertia() 函數添加到 PictureTrackerManager 類 中:
(代碼片段 – MultiTouch – InInertia CSharp)
C#
//We remove the touchID from the tracking map since the fingers are
//no longer touching the picture
public void InInertia(PictureTracker pictureTracker)
{
//remove all touch id from the map
foreach (int id in
(from KeyValuePair<int, PictureTracker> entry in _pictureTrackerMap
where entry.Value == pictureTracker
select entry.Key).ToList())
{
_pictureTrackerMap.Remove(id);
}
}
(代碼片段 – MultiTouch –InInertia VB)
Visual Basic
' We remove the touchID from the tracking map since the fingers are
' no longer touching the picture
Public Sub InInertia(ByVal pictureTracker As PictureTracker)
' remove all touch id from the map
For Each id In (From entry In _pictureTrackerMap _
Where entry.Value Is pictureTracker _
Select entry.Key).ToList()
_pictureTrackerMap.Remove(id)
Next id
End Sub
5.編譯並運行。嘗試將圖片拉出屏幕。試驗各種 Inertia 參數,看它們如何 更改圖片行為。
小結
本實驗改進了一個基於鼠標的簡單圖片處理應用程序,將它升級成了類似於 Surface 的成熟的圖片操作應用程序。您了解了如何檢查是否存在多點觸摸硬件 ,還看到了 Manipulation Processor 的魔力並在實驗最後階段添加了 Inertia 功能。
祝您實驗愉快!