Share via


Running Tracker App

綜述

該實驗室將引導你建立一個執行追踪的 App。這只是一個演示的 App,好讓使用者獲得有關於追蹤的數據並在地圖上顯示追蹤路徑。

App 使用了幾個新的 Windows Phone8 功能,包括新的地圖控制項,地圖的 API,定位服務和背景執行。

Windows Phone 8地圖控制項是一個更新的控制項,可輕鬆透過地圖展示與互動。要獲得目前設備的位置,App將使用Windows Phone定位服務。

註 : Windows Phone8 新的 Maps API 與 Windows Phone7.1 中的 Bing Maps API 不同。在 Windows Phone8 仍然支援 Bing Maps 控件,但不推薦使用。

為了獲得兩地之間地理位置的路徑,App 使用 QueryRoute 類別提供使用者精確的導航點。

背景執行對這個形式的 App 是非常重要的。在 Windows Phone7.1 中,當一個 App 被移動到背景或遭邏輯刪除,正在運行的應用程式代碼將停止運作。在 Windows Phone8 中,即使應用程式被移動到背景,且使用者並沒有積極與 App 互動,應用程式仍被允許繼續運行並且追蹤使用者活動。

本實驗將引導你完成所需的步驟,建立一個擁有上述新功能的 App。

目標

實驗要完成以下目標:

  • 使用地圖控制項

  • 使用 Maps API

  • 使用背景執行

系統需求

您必須符合以下系統需求:

  • • Microsoft Visual Studio Express 2012 for Windows Phone available at 或 Microsoft Visual Studio 2012 with the Windows Phone SDK installed

  • Windows phone 開發經驗

實驗架構

包含兩部分的練習及以下任務:

  1. 更新應用程式清單

  2. 使用新的地圖控制項與 Map APIs

  3. 設定並實作背景執行

  4. 測試

預計完成時間

需要至少 60 分鐘

練習 1

在本練習中,我們將建立一個新的 Windows Phone App,使用新的地圖控制項及 Maps API 以單一地圖顯示兩個地理位置之間的路線。在這一部分中,我們將增加一些稍後在這個實驗中可以使用的 UI 元素。這個練習不使用定位服務,並將模擬的座標資訊直接寫在程式碼內。

任務 1 – 建立 App 並做初步的應用程式清單更改

這個任務會引導你在過程中建立一個新的 Windows Phone 8 App 及透過更改應用程式清單來為後續步驟做準備,使 App 可以使用地圖控制項。Running Tracker App 使用的地圖控制,需要在其應用程式清單裡聲明 ID_CAP_MAP的功能。

  1. 打開 Visual Studio 2012 Express for Windows Phone

  2. 建立一個新的 Windows Phone 8 Application 並命名為 RunningTracker

  3. 使用方案總管,找到 Properties 資料夾內的 WMAppManifest.xml 檔案。雙擊滑鼠左鍵打開應用程式清單設計頁。

  4. 切換到 Capabilities 部分,找到並勾選 IC_CAP_MAP 功能 :


    圖 1
    應用程式清單內的功能部分

  5. 將更改存檔。現在,應用程式清單已經更新好,我們可以繼續在下一個任務中增加用戶介面。

任務 2 – 建立應用程式的使用者介面

在這個任務中,我們將在 App 增加初始的使用者介面。Running Tracker App 是一個我們將實作在 MainPage.xaml 僅有一個頁面的簡單應用程式。在此任務中,您將修改頁面的主要部分,頁面必須包含一個佔據大部分畫面的地圖控制項,及數個代表不同的應用程式序狀態和消息的 TextBlock,和一個來啟動和停止主要功能的按鈕。

  • 更改 MainPage.xaml 檔案 :

    1. 打開 MainPage.xaml 檔案

    2. 找到 StackPanel 並將它命名為 “TitlePane”

    3. 在 StackPanel,更改第一個 TextBlock的Text 屬性為 “Running Tracker”:

      XAML
      <TextBlock Text="Running Tracker" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/>

    4. 更改第二個 TextBlock 的 Text 屬性為 “Let’s run!”:

      XAML
      <TextBlock Text="Let's Run!" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>

    5. 現在標題已經實現了,我們可以建立畫面的主要內容。找到名為 ContentPanel的grid 並定義當中三排如下:

      XAML
      <Grid.RowDefinitions>
      <RowDefinition Height="*"/>
      <RowDefinition Height="Auto"/>
      <RowDefinition Height="Auto"/>
      </Grid.RowDefinitions>

      在這個代碼片段中,我們宣告第一行將盡可能取得多點可使用空間(我們將在稍後使用它做為地圖控制項); 第二和第三排將被指定為 TextBlocks,作為訊息及控制按鈕。

      註 : 稍後我們將繼續增加更多使用者介面地控制項。

    6. 現在我們要增加 "Start" / "Stop" 按鈕. 並在前項 (有 grid 列定義的) 後方新增下列 XAML 代碼 :

      XAML
      <Button Grid.Row="1" Content="Start" x:Name="btnStartStop" Click="btnStartStop_Click" MinWidth="200" Height="72" VerticalAlignment="Top"/>

      這個代碼新增了一個新的按鈕到畫面上,按鈕將被用於開始或者停止指令;我們將根據隱藏代碼 (C#) 檔案的應用程式狀態把文字檔案從“Start”改為“Stop”。

    7. 在接下來的步驟中,將在圖面上增加地圖控制項。地圖控制項的類別屬於 Microsoft.Phone.Maps.Controls 命名空間,這意味著在使用它之前,我們要聲明其 XML 命名空間。找到電話的 PhoneApplicationPage 標籤並增加下面的 XML 命名空間定義到其他標籤後方:

      XAML
      xmlns:maps="clr-namespace:Microsoft.Phone.Maps.Controls;assembly=Microsoft.Phone.Maps"

    8. 現在我們可以在 XAML 中聲明地圖控制項,找到檔案中的按鈕位置並在按鈕宣告的右邊增加下列代碼區塊:

      XAML
      <maps:Map x:Name="map" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Visibility="Collapsed"/>

      註 : 此代碼片段在圖面上增加一個對使用者隱藏的地圖控制項。在這個實驗中,稍後我們將在初始化和獲取位置資訊後增加代碼使得可以顯示地圖。

    9. 最後,當地圖控制項沒有顯示給使用者時,我們增加 TextBlock 顯示並增加代碼片段在前個步驟的的圖控制項後方:

      XAML
      <TextBlock Text="Tap the 'Start' button when ready" HorizontalAlignment="Center" VerticalAlignment="Center" x:Name="txtMessage"/>

    10. 在目前這個階段,畫面已準備好了,但因為一些在 XAML 文件中的事件宣告尚未在 C# 代碼隱藏文件中實作,使得項目無法編譯。

      這項工作將在未來任務完成。

任務 3 – 從代碼隱藏檔案使用 Maps API 及地圖控制項

Running Tracker App 讓使用者能夠在慢跑、騎自行車、或徒步旅行當下追踪他們的位置。在此任務中,將使用 Maps API 計算兩個地理位置間的路徑,並顯示在地圖上。在這個任務中,我們還不會使用 Windows Phone 定位服務,而會使用靜態的坐標模擬行進路徑來代替。

註 : 定位服務將在練習二中介紹。

這個任務著重在以編程方式處理地圖控制項,及使用 RouteQuery 類別 (Microsoft.Phone.Maps.Services 命名空間的一部分) 支援導覽。

  1. 打開 MainPage.xaml.cs 檔案,在開始的地方找到“using”部分,並增加下面的代碼來聲明後續步驟所需的命名空間:

    C#
    using Microsoft.Phone.Maps.Controls;
    using Microsoft.Phone.Maps.Services;
    using System.Device.Location;

  2. 現在讓我們在類別新增一些內容,在“//Constructor” 註解前方新增下列代碼:

    C#
    private const double SourceLatitude = 48.85815; //Eiffel Tower
    private const double SourceLongtitude = 2.29452; //Eiffel Tower
    private const double DestinationLatitude = 48.860395; //The Louvre
    private const double DestinationLongtitude = 2.337599; //The Louvre

  3. 接著,新增一些類別成員在上面的代碼後方。

    C#
    RouteQuery routeQuery = new RouteQuery( );
    List<GeoCoordinate> waypoints = new List<GeoCoordinate>( );

    不變的坐標將被用來計算法國巴黎的艾菲爾鐵塔和盧浮宮博物館兩個熱門地標之間的距離和路線。RouteQuery 類別將被用來計算任兩地或更多地理位置間的路徑。在此練習中查詢結果將被用於在地圖上繪製路線,並在接下來的練習中計算從源頭到目的地的距離。要計算路徑,RouteQuery 類別需要 GeoCoordinate 物件的列表。Waypoints 變數將提供這些座標。最後,GeoCoordinate 類別(來自 System.Device.Location 命名空間)以經度和緯度表示地理座標的位置。

  4. 要初始化 RouteQuery 類別和定義地圖控制項的幾個屬性,我們將使用到 OnNavigatedTo 方法。這個方法繼承了 Page 基本類別,當一個頁面成為一個框架中的活動頁面時會被自動調用。在類別的建構函數之後增加以下代碼:

    C#
    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
    map.ColorMode = MapColorMode.Light;
    map.CartographicMode = MapCartographicMode.Road;
    map.LandmarksEnabled = true;
    map.PedestrianFeaturesEnabled = true;
    map.ZoomLevel = 17;

    routeQuery.TravelMode = TravelMode.Walking;
    routeQuery.QueryCompleted += rq_QueryCompleted;

    base.OnNavigatedTo(e);
    }

    註 : 也可以直接從 XAML 更改各種地圖控制項的屬性(如 ColorMode,LandmarksEnabled 和其他)。

    上面的代碼前幾行設定應用程式運行所需的地圖控制項:我們改變了地圖的配色及製圖模式,使行人功能完備並配置了縮放級別。

    接下來,我們以應用程式所需的行駛方式來初始化 RouteQuery 對象。這是步行模式,因為 App 是打算用來記錄慢跑、騎自行車或徒步旅行活動。 RouteQuery 的功能需要網路連結,並且使用非同步呼叫模式,這就是為什麼查詢成功回傳資料時,我們必須引用回呼函數。

  5. 如上所述,RouteQuery 提供了一個非同步方法以獲得兩個地點之間的路線,我們必須提供一個事件處理方法來處理查詢完成的資料。在前面的方法中增加以下代碼:

    C#
    void rq_QueryCompleted(object sender, QueryCompletedEventArgs<Route> e)
    {
    if (null == e.Error)
    {
    //Recommended way to display route on map
    Route MyRoute = e.Result;
    MapRoute MyMapRoute = new MapRoute(MyRoute);
    map.AddRoute(MyMapRoute);
    }
    else
    MessageBox.Show("Error occured:\n" + e.Error.Message);
    }

    收到查詢結果後,我們創建一個新的 MapRoute 對象來表示接收到的路線,並使用 AddRoute 方法把它增加到地圖。

  6. 最後,我們需要增加一個在任務 2 中宣告的按鈕事件處理器。

    立即在前面的代碼區塊中增加以下代碼:

    C#
    private void btnStartStop_Click(object sender, RoutedEventArgs e)
    {
    map.Center = new GeoCoordinate(SourceLatitude, SourceLongtitude);
    map.Visibility = System.Windows.Visibility.Visible;

    waypoints = new List<GeoCoordinate>
    {
    new GeoCoordinate(SourceLatitude, SourceLongtitude),
    new GeoCoordinate(DestinationLatitude, DestinationLongtitude)
    };

    if (!routeQuery.IsBusy)
    {
    routeQuery.Waypoints = waypoints;
    routeQuery.QueryAsync();
    }
    }

    當用戶點擊 "Start" / "Stop" 按鈕時,此方法將處理事件。目前的練習,我們只將按鈕作為 "Start" 鍵來使用。

    首先,此方法將地圖中心設定在起始位置的坐標,並且以是否隱藏來控制畫面。地圖控制項會將提供的座標顯示在中間。

    要使用 RouteQuery 類別來計算路線,我們需要提供地理坐標表。我們用早先在本練習中直接寫在程式碼內的來源和目的座標常數做為初始化 wayPoints 變數的資料。

    呼叫 QueryAsync 方法後,RouteQuery 目標進行非同步的查詢。這意味著:

    • 操作可能需要相當長的時間才能完成(幾秒鐘)

    • 當等待查詢的結果時,應用程式的使用者界面沒有堵塞。

    這意味著,在這個例子中,在收到以前的查詢結果之前,用戶可以再次單擊“Start”按鈕。為了避免在收到上一個查詢的結果前呼叫 QueryAsync,上面的代碼檢查 RouteQuery 狀態,以檢索 IsBusy 屬性來確保先前的查詢尚未處理。

    註 : 前面的查詢處理已完成後,試著引用 QueryAsync 方法。(除非使用 CancelAsync 方法將它取消),將會以訊息引發 InvalidOperationException,該訊息說:“目前有一個查詢正在進行,無法啟動另一個查詢”。

  7. App 已經完成。可以編譯、配置和執行 App 了。


    圖 2
    應用程式首頁

    點擊“Start”按鈕。從艾菲爾鐵塔到盧浮宮博物館的路線已計算好並且在地圖上顯示:


    圖 3
    地圖上的地標和路線顯示

  8. 第一個練習到此結束。停止執行 App 並回到 Visual Studio。在接下來的練習中,我們增加定位服務來追踪使用者所在的位置,並增加支援後台執行的功能。

練習 2

到目前為止,我們所建立的 App 沒有使用定位服務,將使用者從一個地方導航到另一個地方。相反的,我們依賴於一組靜態的來源和目的地坐標,並直接寫在 C# 代碼中。在本練習中,我們將增加支援位置鎖定的功能。

為了要增加位置追踪到 Running Tracking,我們將不得不更改應用程式清單,使用定位服務,並在地圖上顯示位置訊息。最後,我們將在 App 中增加支持後台運行的功能。

註 : 本練習依賴在前面的練習中建立的代碼,並遞增式的增加它的應用。如果你是從這個練習或跳過前面的練習開始的,你應該使用實驗提供的“Begin”解決方案。“Begin”解決方案位於實驗安裝夾中,在“Sources\EX2 - Location Services\Begin”資料夾內。

任務 1 –更改應用程式清單

應用程式的目標是在使用者活動間追踪使用者的當前位置,這意味著它必須保持動態持續工作。在這期間用戶可能不會使用電話或可能會切換到另一個 App。預設情形下,App 開關將關閉我們的 App,它會停止紀錄追蹤資料、時間和與目的地的距離。

為了在背景中追踪使用者的位置,我們將改變應用程式清單。

註 : 作為商品販售的 App,伺服器將負責檢索使用者擁有的所有會員卡,或負責建立新的會員卡並將其保存到電子錢包中。

  1. 使用方案總管,移到 Properties 資料夾中找到 WMAppManifest.xml 檔案。按左鍵雙擊打開應用程式清單設計頁。

  2. 切換到 Capabilities,勾選 IC_CAP_LOCATION 功能:


    圖 4
    在應用程式清單中啟用 Location Support

  3. 接下來,我們要啟用背景執行。清單設計頁不支援這部分,我們只能以手動更改。關閉清單設計頁和在 XML 編輯器中打開清單:

    按右鍵點擊 WMAppManifest.xml 檔案,並從目錄中點選“Open With… ”:


    圖 5
    File Context 目錄中的Open With 選項

  4. 從 Open With 對話框中選擇“XML (Text) Editor” 並點選 OK :


    圖 6
    XML 編輯器選擇對話框

  5. 在 XML 編輯器中打開清單。找到 Tasks 下方的 DefaultTask 元素。

  6. 用下面的代碼更換 DefaultTask 元素:

    XML
    <DefaultTask Name="_default" NavigationPage="MainPage.xaml" >
    <BackgroundExecution>
    <ExecutionType Name="LocationTracking" />
    </BackgroundExecution>
    </DefaultTask>

    這個更改使 App 可以在後台保持執行狀態並追踪使用者的位置。在 Windows Phone 8 中,追蹤位置的 App 可以持續在後台追踪使用者的所在位置,即使在用戶離開到另一個應用程式後。

  7. 現在 App 已經準備好可以做下列任務中的代碼更改。

任務 2 –使用定位服務和處理後台執行

從這一刻起,App 將使用即時位置訊息取代前面的練習中建立的靜態假坐標。我們將更改幾種方法,並修改使用者介面來顯示使用者的進度。

  1. 修改應用程式清單以支援後台執行後,需要進一步的修改代碼。找到並打開 App.xaml 檔案。找到 shell:PhoneApplicationService 元素,並增加下列代碼到“/>”標籤前方:

    XAML
    RunningInBackground="Application_RunningInBackground"

  2. 為 RunningInBackground 事件註冊,該事件已被增加在代碼隱藏文件中。打開 App.xaml.cs 檔案,並增加下面的事件處理器方法到類別中:

    C#
    private void Application_RunningInBackground(object sender, RunningInBackgroundEventArgs e)
    {
    IsInBackground = true;
    }

  3. 在類別中增加一個新的靜態欄位 :

    C#
    public static bool IsInBackground = false;

  4. 找到並打開 MainPage.xaml 檔案

  5. 找到 ContentPanel 的 Grid 元素,並增加以下代碼到“</Grid>”結束標籤前:

    XAML
    <StackPanel Grid.Row="2" Orientation="Horizontal"
    HorizontalAlignment="Stretch" x:Name="stkWorkoutDetails">
    <TextBlock Text="Workout details: "/>
    <TextBlock Text="{Binding Mileage, StringFormat=\{0:F\} mi.}"/>
    <TextBlock Text=" in "/>
    <TextBlock Text="{Binding Runtime, StringFormat=\{0:hh\\:mm\\:ss\} minutes}"/>
    </StackPanel>

    註 : 此代碼定義了一個行 Mileage 和運 Runtime 的數據綁定,將在此任務中後續內容中定義。有關數據綁定的更多資訊,請參閱 Windows Phone 的說明文件。

  6. 找到並打開 MainPage.xaml.cs 檔案。

  7. 在類別開端增加下列 “using” 陳述式 :

    C#
    using System.Windows.Media;
    using System.Diagnostics;

  8. 刪除以下類別中定義的常數:SourceLatitude,SourceLongtitude,DestinationLatitude,DestinationLongtitude。

  9. 增加下列欄位取代剛才刪除的那些 :

    C#
    private const float KM_MILE = 0.000621371192f;

    GeoCoordinateWatcher gcw;
    bool isRunning = false;
    int count = 0;

    MapLayer historicalReadingsLayer = new MapLayer( );
    MapOverlay overlay = new MapOverlay( );
    MapPolyline polyline = new MapPolyline( );
    TextBlock txtCurrentSpeed = new TextBlock( );

    List<GeoPosition<GeoCoordinate>> positions = new List<GeoPosition<GeoCoordinate>>( )

    KM_MILE 常數將被用來轉換從公尺(RouteQuery 類別返回的單位)到英里的距離。

    Windows Phone 8中 GeoCoordinateWatcher(從 System.Device.Location 命名空間)提供的定位服務將被用於追踪使用者的位置。

    Microsoft.Phone.Maps.Controls 名稱中的 MapLayer、MapOverlay 和 MapPolyline 類別,將用於在地圖上繪製行駛路線。

    MapLayer 類別表示地圖控制項頂端的一個繪製圖層,它顯示 MapOverlay 對象的集合。

    MapOverlay 類別包含了 UIElements 的集合,有助於使用地理坐標位置來定位。

    MapPolyline 類別表示地圖控制項上將被用於繪製行駛路線的多斷折線(這是一條由多個直線段組成的線)。

    最後,“positions”列表將用於累加在行進中 App 檢索出的位置,並計算目前走了多遠的距離。

  10. 在 MainPage 類別尾端增加下列代碼:

    C#
    public float Mileage
    {
    get { return (float)GetValue(MileageProperty); }
    set { SetValue(MileageProperty, value); }
    }

    public static readonly DependencyProperty MileageProperty =
    DependencyProperty.Register("Mileage", typeof(float), typeof(MainPage), new PropertyMetadata(0.0f));

    public TimeSpan Runtime
    {
    get { return (TimeSpan)GetValue(RuntimeProperty); }
    set { SetValue(RuntimeProperty, value); }
    }

    public static readonly DependencyProperty RuntimeProperty =
    DependencyProperty.Register("Runtime", typeof(TimeSpan), typeof(MainPage), new PropertyMetadata(TimeSpan.Zero));

    此代碼將增加兩個相依性屬性用來顯示行進的進度(移動的距離及一開始行進的時間)。

  11. 為了使先前代碼片斷中增加的螢幕元素及屬性間數據綁定,找到類別的建構函數,並在 InitializeComponent 方法呼叫後方增加下面一行:

    C#
    stkWorkoutDetails.DataContext = this;

  12. 找到 OnNavigatedTo 方法。在開端加入以下 GeoCoordinateWatcher 初始化代碼:

    C#
    gcw = new GeoCoordinateWatcher(GeoPositionAccuracy.High);
    gcw.PositionChanged += gcw_PositionChanged;
    gcw.StatusChanged += gcw_StatusChanged;

    這段代碼建立了一個新的 GeoCoordinateWatcher 類別的例子,並要求高準確性或需要報告使用者位置的精確追蹤結果。此代碼還訂閱了 PositionChanged和StatusChanged 事件。

  13. 接下來,仍然在 OnNavigatedTo 方法,找到改變 routeQuery.TravelMode 的幾行和訂閱 routeQuery.QueryCompleted 的事件,用下面的代碼替換他們:

    C#
    if (!App.IsInBackground)
    {
    txtCurrentSpeed.Foreground = new SolidColorBrush(Colors.Black);
    overlay.Content = txtCurrentSpeed;

    routeQuery.TravelMode =
    Microsoft.Phone.Maps.Services.TravelMode.Walking;
    routeQuery.QueryCompleted += rq_QueryCompleted;

    MapLayer currentSpeedLayer = new MapLayer();
    currentSpeedLayer.Add(overlay);
    map.Layers.Add(currentSpeedLayer);
    map.Layers.Add(historicalReadingsLayer);
    map.MapElements.Add(polyline);
    }

    首先,這個代碼可以確保執行初始化之前,App 不在後台運行。

    註 : 當一個位置追踪 App 在後台持續保持運作時,這意味著從背景返回時,不需要重新初始化。

    txtCurrentSpeed 變數是一個將被動態增加到地圖控制項的 TextBlock 元素,並顯示目前的讀取速度。
    初始化 RouteQuery 對象後,代碼初始一個新的 MapLayer 對象,這是用來顯示在地圖控制項中的路徑、速度和追踪的歷史位置。

  14. 接下來,增加下面的代碼,它實作了 GeoCoordinateWatcher StatusChanged 事件處理器:

    C#
    void gcw_StatusChanged(object sender, GeoPositionStatusChangedEventArgs e)
    {
    Debug.WriteLine("New status: " + e.Status);

    if (e.Status == GeoPositionStatus.Ready)
    {
    map.Center = gcw.Position.Location;
    polyline.Path.Clear();

    btnStartStop.Content = "Stop";
    map.Visibility = System.Windows.Visibility.Visible;

    Mileage = 0;
    Runtime = TimeSpan.Zero;
    }
    }

    此代碼片段會將新位置狀態輸出到 Debug 控制台(我們將在任務 3 使用它),當定位服務完成時,會將取到的位置設定給地圖的中心。然後,此方法為新的執行階段準備地圖、變數、UI 元素。

  15. 接下來,增加下面的代碼實作 GeoCoordinateWatcher PositionChanged 事件處理器:

    C#
    void gcw_PositionChanged(object sender,
    GeoPositionChangedEventArgs<GeoCoordinate> e)
    {
    Debug.WriteLine("New position:" + e.Position.Location.Latitude + ","
    + e.Position.Location.Longitude);

    map.Center = e.Position.Location;
    map.Heading = e.Position.Location.Course;

    count++;

    polyline.Path.Add(e.Position.Location);

    if (count > 1)
    {
    txtCurrentSpeed.Text = e.Position.Location.Speed + "m/s";
    overlay.GeoCoordinate = e.Position.Location;
    }

    if (positions.Count > 0)
    {
    MapOverlay ovrl = new MapOverlay();
    TextBlock txtTimestamp = new TextBlock();
    txtTimestamp.Foreground = new SolidColorBrush(Colors.Black);
    ovrl.Content = txtTimestamp;
    ovrl.GeoCoordinate = positions.Last().Location;
    txtTimestamp.Text = string.Format("{0:hh\\:mm\\:ss}",
    positions.Last().Timestamp.TimeOfDay);
    historicalReadingsLayer.Add(ovrl);
    }

    positions.Add(e.Position);
    waypoints.Add(e.Position.Location);

    if (!routeQuery.IsBusy && count > 1)
    {
    routeQuery.InitialHeadingInDegrees =
    e.Position.Location.Course;
    routeQuery.Waypoints = waypoints;
    routeQuery.QueryAsync();
    }
    }

    每當系統的定位服務提供新的位置訊息,這方法就會被呼叫。它是負責置中使用者目前的所在位置並顯示圍繞周圍的地圖,計算和顯示當前的時間和速度,並在地圖上繪製線路表示運行的軌跡。

    前面的練習中,只有當 RouteQuery 不是還在忙於處理先前的請求時,最後一個片段裡新的 waypoint 的 “routeQuery”成員才會呼叫非同步的“QueryAsync”方法。

  16. 接下來,修改前面的練習中建立的 QueryCompleted 的事件處理器。找到 rq_QueryCompleted 方法,並用下面的代碼替換其內容:

    C#
    TimeSpan timeDiff = positions.Last().Timestamp.TimeOfDay -
    positions.First().Timestamp.TimeOfDay;

    Mileage = float.Parse(e.Result.LengthInMeters.ToString()) * KM_MILE;
    Runtime = timeDiff;

    Debug.WriteLine("Passed: " + Mileage + " miles. in " +
    string.Format("{0:hh\\:mm\\:ss}", Runtime));

    現在,這個方法計算總共的行進時間和行駛里程,並將它們分配給本練習開始時聲明的屬性。

    註 : 里程和運行時間的屬性綁定到螢幕 TextBlocks,每當屬性被指定,會導致螢幕上的資訊自動更新。

  17. 在前面的練習中的“Start”按鈕,被用來啟動新的行進階段。我們現在實作了設計好的完整 "Start"/"Stop" 機制。

    要做到這一點,找到 btnStartStop_Click 的事件處理器方法,並用下面的代碼取代:

    C#
    if (!isRunning)
    {
    map.Visibility = Visibility.Collapsed;
    txtMessage.Text = "Getting ready...";
    gcw.Start();
    polyline.Path.Clear();

    isRunning = true;
    }
    else
    {
    gcw.Stop();

    btnStartStop.Content = "Start";
    isRunning = false;
    }

    如果 App 目前尚在追蹤位置資訊且使用者處於靜止狀態或下了停止指令,此代碼啟動 GeoCoordinateWatcher(例如,當用戶處於行進階段的中間)。

  18. 現在你可以建立並執行你的 App,測試它並進行下一階段的任務。

任務 3 –測試

要測試 App,我們需要模擬系統定位服務報告的位置。我們可以使用實體設備執行 Windows Phone 8,但是有個更加容易的選擇是使用 Windows Phone8 模擬器。它提供位置模擬設備,我們將使用此設備在這個任務中測試定位服務。

  1. 編譯和配置 App 到 Windows Phone 模擬器,並執行 App。

  2. 在模擬器主螢幕上,你會看到右上角的選項列。點選“>>”按鈕顯示一個額外的“工具”面板:


    圖 7
    從模擬器打開額外的工具列

  3. 點選 “Location”


    圖 8
    從模擬器打開額外的工具列

    正如你可以看到圖中的“Location”選項卡中顯示了一個地圖,可以用來模擬設備的位置(實際上,模擬從一點到另一點的移動)。你可以透過點擊地圖來模擬移動,它會對模擬器發出一個 GPS 位置變更事件,或由記錄數據模擬行進路線傳回模擬器。藉由記錄路徑和傳回資訊,你可以不必重複點擊地圖就測試一組已知的路線。您還可以控制模擬器中模擬移動事件所發出的頻率。

  4. 讓我們回到 Running Tracker App。點擊 "Start" 按鈕,然後點擊模擬器地圖來模擬路線。App 中應顯示出一條代表路線的藍線:


    圖 9
    使用 Windows Phone 模擬器模擬位置變更

  5. 要測試應用程式的後台運行,請按一下該設備的 "Home" 鍵,關閉 App。多做幾次點擊模擬器地圖的動作,對模擬器發出額外移動的訊號。


    圖 10
    當應用程式在背景執行時模擬事件

    如果 App 附屬的調試器正在運作,瀏覽到 Visual Studio2012 的 Output 工具窗口,並觀察打印的除錯輸出,即使 App 上在背景運作:


    圖 11
    Visual Studio 中的除錯輸出

    這意味著,即使當 App 不在前台但仍然運行時,從定位服務接收事件並正確地處理它們。

  6. 點擊設備模擬器上 "Back" 按鈕,重新啟動 App 並檢查完整路徑。


    圖 12
    應用程式重新啟動以後更新路

  7. 練習到此結束

總結

在本次實驗中,你試驗了數個 Windows Phone 8 的功能:

  • 使用地圖控制項

  • 整合地圖與定位服務

  • 使用 Maps API

  • 在背景執行應用程式

這些功能對許多 App 是極為重要的,並且可以幫助您擴展應用程式的功能以滿足使用者的需求。

這個實驗裡開發的 "Running Tracker" App,是示範如何獲得開發一個擁有上述功能的 Windows Phone 8 App 所需要的基本技能。

返回目錄頁