程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> Windows 7開發:多點觸摸 - 管理(動手實驗)(下)

Windows 7開發:多點觸摸 - 管理(動手實驗)(下)

編輯:關於.NET

(代碼片段 – 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 功能。

祝您實驗愉快!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved