Il presente articolo è stato tradotto automaticamente.

Windows Phone 8.1)

添加到 Windows Phone 8.1 地圖控制項的應用程式資料

Keith Pijanowski

下載代碼示例

在我一 11 月關於映射功能的 Windows Phone 8.1 的文章,我介紹了 Windows Phone 8.1 地圖控制項和映射服務 API。我展示了如何使用地圖控制項添加到電話應用程式,例如,映射功能添加圖像來標記一個指定的位置,計算一個指定的位址 (編碼) 的地理座標,確定指定的地理座標 (反向地理編碼)、 位址和提供開車和走路的方向。

這篇文章將演示如何通過將控制項添加到地圖控制項使用 XAML 和應用程式資料繫結到這些控制項進入地圖控制項的應用程式資料。如果您的應用程式將使用離線,以及,亦可供離線使用由地圖控制項使用的基礎資料。這使得地圖控制項以適應您的應用程式的離線功能。我還會展示如何離線地圖控制項並使離線資料保持最新。

將控制項添加到使用 XAML 的地圖控制項

在我上一篇文章中,我用代碼來將橢圓控制項添加到一張地圖,以繞圓圈在地圖上的特定位置。這是一種好方法,如果您需要完全控制。然而,如果你想要得到創造性和批註圖做了很多不同類型的控制項,使用代碼可以笨拙。將控制項添加到地圖使用 XAML 是效率更高。此外,XAML 方法是容易得多時您需要映射集合內使用資料繫結的一張地圖的位置。

首先,我將展示如何將控制項使用 XAML 添加以及如何將應用程式資料繫結到這些控制項。然後我將深入進一步成資料繫結和顯示如何資料繫結到該地圖控制項位置的集合。

添加基本的 XAML 控制項有兩種方式將控制項添加到地圖控制項,以將應用程式資料添加到映射:您可以將控制項添加為地圖控制項的子控制項或您可以使用 MapItemsControl 來包含的控制項。

圖 1 演示如何將控制項添加為地圖控制項的子級。因為兒童是地圖控制項的預設內容屬性,它不需要顯式指定在 XAML 標記中。圖 2 顯示將控制項添加到地圖的控制,這使得使用的 MapItemControl 包含已添加的控制項的另一種方法。

圖 1 為地圖控制項的子控制項中添加控制項

<Maps:MapControl
  x:Name="myMapControl" Grid.Row="1"
  MapServiceToken="{StaticResource MapServiceTokenString}" >
  <!-- Progress bar which is used while the page is loading. -->
  <ProgressBar Name="pbProgressBar" IsIndeterminate="True" Height="560"
    Width="350" />
  <TextBlock Name="tbMessage" Text="{Binding Message}"
    Maps:MapControl.Location="{Binding Location}"  
    Maps:MapControl.NormalizedAnchorPoint="1.0,1.0"
    FontSize="15" Foreground="Black" FontWeight="SemiBold"
    Padding="4,4,4,4"
    Visibility="Collapsed"
    />
  <Image Name="imgMyLocation" Source="Assets/PinkPushPin.png"
    Maps:MapControl.Location="{Binding Location}"
    Maps:MapControl.NormalizedAnchorPoint="0.25, 0.9"
    Height="30" Width="30"
    Visibility="Collapsed" />
</Maps:MapControl>

圖 2 包含控制項內 MapItemControl

<Maps:MapControl
  x:Name="myMapControl"
  MapServiceToken="{StaticResource MapServiceTokenString}">
  <Maps:MapItemsControl>
    <TextBlock Name="tbAddress" Text="{Binding Message}"
      Maps:MapControl.Location="{Binding Location}"
      Maps:MapControl.NormalizedAnchorPoint="1.0,1.0"
      Visibility="Collapsed" />
    <Image Name="imgMyLocation" Source="Assets/PinkPushPin.png"
      Maps:MapControl.Location="{Binding Location}"
      Maps:MapControl.NormalizedAnchorPoint="0.25, 0.9"
      Height="30" Width="30"
      Visibility="Collapsed"/>
  </Maps:MapItemsControl>
</Maps:MapControl>

如果您使用中所示的 MapItemControl 技術圖 2,會意識到你將無法訪問您的代碼隱藏檔中的控制項。IntelliSense將確認您的控制項名稱作為有效的變數,但在運行時這些變數將始終為 null,如果你引用它們你會舉出。MapItemControl 通常用於包含用於將物件的集合綁定到地圖控制項的資料範本。(這會將討論在本文稍後部分。因此,如果你不綁定到的物件的集合,它是更好地將您的控制項添加為地圖控制項的子級中所示圖 1

資料繫結 中的代碼 圖 1 使用資料繫結來設置影像控制和文字區塊的位置屬性。Text 屬性的 TextBlock 還利用資料繫結。要快速查看,位置屬性是類型的附加的屬性 Geopoint。它用來指定在地圖上將放置該控制項的位置。NormalizedAnchorPoint 附加屬性允許將微調控制項的位置。例如,您可以使用 NormalizedAnchorPoint 屬性來中心位置的控制權或放置控制項左上角的位置上。在我第一篇文章中詳細討論了這兩個屬性 (msdn.microsoft.com/magazine/dn818495)。

資料繫結允許 XAML 控制項從底層物件中獲取其值。從下面的類創建的物件將用於保存中所示的 XAML 控制項所需的值圖 1

public class LocationEntity
{
  public Geopoint Location { get; set; }
  public string Message { get; set; }
}

圖 3 顯示完整的 OnNavigatedTo 事件,對於包含在控制項的網頁圖 1。(如果某個頁面或應用程式中的視圖需要大量的安裝程式,考慮將此代碼放置在創作中一個視圖模型,並以非同步方式運行)。此代碼將設置設備的當前的位置成以及短消息 LocationEntity 類的一個實例。LocationEntity 物件被設置到 DataCoNtext 屬性中地圖控制項的通知。

圖 3 OnNavigatedTo 事件創建物件所需的資料繫結

protected async override void OnNavigatedTo(NavigationEventArgs e)
{
  // Call the navigation helper base function.
  this.navigationHelper.OnNavigatedTo(e);
  // Get the user's current location so that it can be
  // used as the center point of the map control.
  Geolocator geolocator = new Geolocator();
  // Set the desired accuracy.
  geolocator.DesiredAccuracyInMeters = 200;
  // The maximum acceptable age of cached location data.
  TimeSpan maxAge = new TimeSpan(0, 2, 0);
  // Timeout used for the call to GetGeopositionAsync.
  TimeSpan timeout = new TimeSpan(0, 0, 5);
  Geoposition geoposition = null;
  try
  {
    geoposition = await geolocator.GetGeopositionAsync(maxAge, timeout);
  }
  catch (Exception)
  {
    // Add exception logic.
  }
  // Set up the LocationEntity object.
  LocationEntity locationEntity = new LocationEntity();
  locationEntity.Location = geoposition.Coordinate.Point;
  locationEntity.Message = "You are here";
  // Specify the location that will be at the center of the map.
  myMapControl.Center = locationEntity.Location;
  // Set the map controls data context so data binding will work.
  myMapControl.DataContext = locationEntity;
  // Zoom level.
  myMapControl.ZoomLevel = 15;
  // The map control has done most of its work. Make the controls visible.
  imgMyLocation.Visibility = Windows.UI.Xaml.Visibility.Visible;
  tbMessage.Visibility = Windows.UI.Xaml.Visibility.Visible;
  // Collapse the progress bar.
  pbProgressBar.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
}

幾個小貼士

在所示的代碼圖 3,OnNavigatedTo 事件執行耗時的工作。具體而言,這一事件喚起定位器物件的 GetGeopositionAsync 功能。這個函數獲取該設備當前的位置,可以在地圖上正確放置影像控制和 TextBlock 控制項之前,需要。在這種情況下,作為兒童通過 XAML 添加到地圖的任何控制項最初會顯示在地圖的左上角,直到他們可以在地圖上定位。這將創建差 ux 選項。若要更正此問題,只是設置任何已添加的控制項作為在 XAML 中的折疊。可以使添加的控制項可見,一旦控制位置的計算和設置,這些控制項將綁定的物件。(指圖 1 和代碼中的最後幾行圖 3.)

請考慮使用定位器物件的 DesiredAccuracyInMeters 屬性。將此屬性設置為 100 米或更少,會得到最準確的資料。如果設備有 GPS 功能,然後將使用 GPS 來確定設備的當前的位置。如果此值大於 100 米,定位器的物件將優化電源,並使用非 GPS 資料,如 Wi-Fi 信號。100 米閾值可以改變隨著設備的發展,所以將此屬性設置基於需求的應用程式和不底層的閾值,觸發不同的行為。最後,DesiredAccuracyInMeters 屬性將重寫任何定位器的 DesiredAccuracy 屬性中設置。

此外,請考慮使用 GetGeopositionAsync,接受一個 maximumAge 參數和一個超時參數的重載。最大年齡參數是指定緩存的位置資料的最大可接受的年齡的時間跨度。超時參數也是時間跨度,並將導致 GetGeopositionAsync 函數拋出異常,如果確定當前所在的位置比指定的時間。

前面的兩個技巧將顯著地提高性能。然而,在地區與貧窮的互聯網連接和低的記憶體和 Cpu 較慢的設備上,地圖控制項和映射服務 Api 可能仍然需要時間,導致使用者遇到延遲。在這種情況下,地圖控制項直到進入地圖控制項中心點屬性設置的位置在當前縮放級別會顯示全球地圖。這也是差的使用者體驗,因為使用者應給予工作正在發生一些視覺化的指示。在 XAML 中圖 1,一個進度列作為地圖控制項的子級添加和可見。進度列是設置為不確定因為精確量所需的時間尚不清楚。一旦地圖的中心屬性是計算和設置地圖控制項中,可以折疊進度列。不確定的進度列使用的最佳做法表明他們應始終放在頁面的頂端,對於大多數情況,我同意。然而,當使用地圖控制項,我更願意看到對面地圖的中心顯示進度列。地圖控制項傾向抓住使用者的焦點,為此進度列的頁面頂部很可能被忽視。同時,整個地圖控制項顯示一個進度列告訴使用者它是地圖控制項做的工作。

資料繫結集合

將集合綁定到地圖控制項是類似于將一個集合綁定到一個清單方塊、 清單視圖、 GridView 或顯示集合的任何其他控制項。為了說明這一點與地圖控制項,請考慮下面的類:

public class Team
{
  public string TeamName { get; set; }
  public Uri ImageSource { get; set; }
  public string Division { get; set; }
  public string StadiumName { get; set; }
  public Geopoint StadiumLocation { get; set; }
  public Point NAP { get; set; }
}

此類的實例可用於保存有關專業運動團隊的基本資訊。請注意屬性之一是一個 Geopoint 屬性包含作為球隊的主場體育館的位置。

在 XAML 圖 4 設置地圖控制項,這樣團隊物件的集合,可以綁定到它,並且每個球隊的主場體育館的位置都將標有一個小圖示。

圖 4 為集合綁定設置地圖控制項的

<Maps:MapControl
  x:Name="myMapControl" Grid.Row="1"
  MapServiceToken="{StaticResource MapServiceTokenString}" >
  <Maps:MapItemsControl x:Name="MapItems" >
    <Maps:MapItemsControl.ItemTemplate>
      <DataTemplate>
        <Image Source="{Binding ImageSource}"
          Maps:MapControl.Location="{Binding StadiumLocation}"
          Maps:MapControl.NormalizedAnchorPoint="{Binding NAP}"
          Height="15" Width="15"
          />
      </DataTemplate>
    </Maps:MapItemsControl.ItemTemplate>
  </Maps:MapItemsControl>
</Maps:MapControl>

如果你熟悉其他集合綁定的控制項,沒有在圖 4 應該是不熟悉。影像控制包含在 DataTemplate 中。影像控制的附加屬性綁定到團隊物件的 StadiumLocation 屬性的位置。影像控制也具有一個附加的 NormalizedAnchorPoint 屬性,將綁定到在體育場位置會居中對齊圖像的屬性。

請注意,在地圖控制項綁定到一個集合時,NormalizedAnchorPoint 屬性不能是硬編碼。必須將它綁定到基礎物件中的值。如果您嘗試設置此屬性,像這樣:

Maps:MapControl.NormalizedAnchorPoint="0.5,0.5"

XAML 編輯器不喜歡這種語法和值將不會設置。微軟是意識到了這個問題。

圖 5 顯示地圖控制項顯示 NFL 球場位置。(此螢幕抓圖是從本文附帶的代碼示例。該代碼示例包含此處未顯示為簡潔起見,如具現化集合和正確格式要合身網頁上的控制項的所有輔助代碼)。

全國足球聯賽球場
圖 5 全國足球聯賽球場

縮放控制項

有可能調整控制項大小,所以他們代表指定的距離。例如,你可能想要在你的地圖上顯示的規模。規模為使用者提供了一種視覺化的線索,讓他們去猜在地圖上的物件之間的距離。此外,如果你使用的地圖控制項來描繪一個地點座標,好的辦法做到這一點是圓的將一個橢圓添加到地圖控制項,塑造成一個圓圈,這樣圈子包括地點座標警戒距離大小半徑。

Windows Phone 8.1 中的控制項大小由指定寬度和高度,以圖元為單位。因此,縮放控制項來表示某一距離涉及到確定多少距離由地圖控制項上的單個圖元。這裡是為確定由上地圖控制項的單個圖元的距離方程:

const double BING_MAP_CONSTANT = 156543.04;
double MetersPerPixel =
  BING_MAP_CONSTANT * Math.Cos(latitude) / Math.Pow(2, zoomLevel);

使用的緯度應該來自地圖控制中心屬性。它必須以弧度為單位,不度。因為緯度通常以度為單位表示的你得將其轉換為弧度為單位) 乘以 Pi/180 (Math.PI/180) 的程度值。縮放級別來自地圖控制項的縮放級別,並且是一個從 1 到 20 的值。 在 Windows Phone 8.1,它表示為一張雙人床。

完整的數學推導,此處所示的方程是超出了這篇文章 ; 然而,幾個評論的順序。

第一眼看方程看起來可能不正確。緯度為什麼很重要?地圖的比例只是應該在縮放級別的函數嗎?事實是緯度不要緊,縮放級別僅是不夠的當確定地圖的比例。Bing Maps,是為地圖控制項的後端,利用墨卡托投影。墨卡托投影是表面的球體的一種技術為 (在本例中地球) 細節投射到一個方形的表面。此投影介紹了尺度不一致之處,因為得越遠,你去從赤道,那裡維持一個正方形適合更多伸展運動。一個簡單的實驗可以説明您更好地理解墨卡托投影。剝一個橘子並保存所有的碎片。當完全剝橘子時,把這些碎片重新在一起在一個平面上,努力去完全融入一座呈方形。它是不可能的。這些碎片進入一座呈方形的必由之路是桔子的伸展你"赤道"不是桔子的件。你越接近,"兩極",越伸展你需要做好一個方形的適合。這個拉伸創建規模較接近赤道的地區差異。拉伸所需的金額是距離的從赤道的函數。因此,對緯度的依賴。作為這一伸展在墨卡托投影的地球行動的例子,考慮這兩個城市的加拿大魁北克省和佛羅里達州基韋斯特市 完全放大的視圖 (縮放級別 20) 的魁北克使用地圖控制項將導致代表 33.5 腳的 100 個圖元。基韋斯特的相同的縮放級別會導致代表 44.5 公尺的 100 個圖元。魁北克居民享受是 11 英尺比居民的基韋斯特的規模 — — 小小的安慰,為寒冷的氣候。墨卡托投影的更多資訊,查閱 MSDN 庫文章,"理解規模和決議,"在 bit.ly/1xIqEwC

要注意對方程的最後事實是 Bing 地圖恒定的。Bing 地圖不斷基於地球的半徑和 Microsoft 可以使用來確定指定的縮放級別的地圖視圖的方程。它的單位是米每個圖元。

圖 6 顯示用於作為距離尺規的 textblock) 和添加到地圖控制項的矩形。圖 7 顯示 ZoomLevelChanged 事件並創建距離規模所需的邏輯。(代碼示例檢查 RegionInfo.CurrentRegion.IsMetric 屬性和顯示使用者都更熟悉公制系統度量值)。最後, 圖 8 顯示的代碼示例中的截圖 — — 添加到地圖控制項的距離尺度。

圖 6 Xaml TextBlock 和使用作為距離尺規的矩形

<Maps:MapControl
  x:Name="myMapControl" Grid.Row="1"
  MapServiceToken="{StaticResource MapServiceTokenString}"
  ZoomLevelChanged="myMapControl_ZoomLevelChanged">
  <!-- Distance scale, which is located at the lower left of the Map control. -->
  <TextBlock Name="tbScale" Text="Scale Text" FontSize="15" Foreground="Black"
    Margin="24,530,24,6" Opacity="0.6" />
  <Rectangle Name="recScale" Fill="Purple" Width="100" Height="6"
    Margin="24,548,24,24" Opacity="0.6" />
</Maps:MapControl>

圖 7 ZoomLevelChanged 事件

private void myMapControl_ZoomLevelChanged(MapControl sender, object args)
{
  // Get the Map control's current zoom level.
  double zoomLevel = sender.ZoomLevel;
  // Use the latitude from the center point of the Map control.
  double latitude = sender.Center.Position.Latitude;
  // The following formula for map resolution needs latitude in radians.
  latitude = latitude * (Math.PI / 180);
  // This constant is based on the diameter of the Earth and the
  // equations Microsoft uses to determine the map shown for the
  // Map control's zoom level.
  const double BING_MAP_CONSTANT = 156543.04;
  // Calculate the number of meters represented by a single pixel.
  double MetersPerPixel =
    BING_MAP_CONSTANT * Math.Cos(latitude) / Math.Pow(2, zoomLevel);
  // Aditional units.
  double KilometersPerPixel = MetersPerPixel / 1000;
  double FeetPerPixel = MetersPerPixel * 3.28;
  double MilesPerPixel = FeetPerPixel / 5280;
  // Determine the distance represented by the rectangle control.
  double scaleDistance = recScale.Width * MilesPerPixel;
  tbScale.Text = scaleDistance.ToString() + " miles";
}

D距離尺度添加到地圖控制項顯示日落碼頭在佛羅里達州基韋斯特市
圖 8 距離尺度添加到地圖控制項顯示日落碼頭在佛羅里達州基韋斯特市

下載地圖供離線使用

地圖可以下載供離線使用。這是非常方便的應用程式需要提供映射功能,沒有任何形式的互聯網連接設備時,如當使用者正行駛在一個長的公路之間市區或深藏在樹林裡徒步旅行。

因為它們佔用大量的存儲,不能未經使用者同意以程式設計方式下載的地圖。使用者必須選擇在每次下載到通過使用一個系統 — —­提供了允許的 UX 需選擇並下載的地圖。這被通過使用靜態類 MapManager,屬於 Windows.Services.Maps 命名空間。此類提供對下載的地圖和更新映射函數。這裡所示的 ShowDownloadedMapsUI 函數將啟動內置的地圖應用程式並顯示中顯示的網頁圖 9

MapManager.ShowDownloadedMapsUI();

用於下載地圖的 UI
圖 9 用於下載地圖的 UI

內置的地圖應用程式名地圖中顯示的網頁圖 9 也可以通過點擊下載映射按鈕從設置功能表選項訪問。因為此函數把使用者帶到另一個應用程式 (內置的地圖應用程式),他將不得不手動返回到原始的應用程式。

中顯示的網頁圖 9 顯示先前已下載的所有映射。它還包含一個功能表選項,允許您刪除任何先前已下載的映射存儲在設備上需要被釋放或不再需要一張地圖的情況下。

點擊添加 (+) 按鈕啟動地圖選擇嚮導,顯示一個頁面,允許您指定包含您想要下載的地圖的大陸。一旦選定了一個大洲,將顯示頁,其中顯示在選定的非洲大陸的所有國家。您可以選擇在大陸的所有國家和下載地圖為整個非洲大陸,但這將需要大量的存儲空間。例如,對於美國的所有映射都需要 3.4 GB 的存儲空間。整個大陸的北美洲和中美洲地區將需要更多。

如果您選擇包含多個地區或國家的一個大的國家,你會看到一個頁面,允許您選擇特定區域或國家。您可以通過使用選擇按鈕來選擇多個區域。當指定一個區域時,你會被帶到示的下載頁面圖 10。這個頁面還將是否您選擇一個小的國家,沒有任何地區或國家所示。

下載一張地圖
圖 10 下載一張地圖

在下載之前的任何映射,它是一個好主意,以鼓勵消費者通過去設置應用程式並選擇存儲感檢查設備上的可用空間。這將顯示可用空間在設備上,如空間需要被釋放的情況下使用每個應用程式在設備上的存儲空間。在寫這篇文章的時候,沒有 WinRT Api,這使您可以以程式設計方式確定使用設備上的存儲量或可用存儲量。

它也是一個好的主意來下載地圖雖然連接到不受限制的網路,無線上網等。這篇文章的代碼示例演示如何檢查當前的網路連接,並警告使用者,如果他們是在計量的連接上。

更新已下載的映射

地圖是偶爾更改或修改。新的道路可能會添加到一個城市,街道名稱可能會改變,有時改變了區域的邊界。因此,應定期更新已下載的映射。MapManager 靜態類包含一個功能叫做 ShowMapsUpdateUI 的更新已下載的映射:

MapManager.ShowMapsUpdateUI();

ShowMapsUpdateUI 函數是類似于 ShowDownloadedMapsUI 的功能,因為它具有內置的地圖應用程式使用者。當調用此函數時,所有已下載的映射檢查,看看是否他們需要更新。如果任何先前下載的地圖需要更新,使用者會告訴更新的大小,並給出了選擇取消或繼續執行下載。這相同的功能也是從設置功能表選項的地圖應用程式可用。

如果您的應用程式鼓勵下載地圖,利用 ShowDownloadedMapsUI,它是最佳的做法,也使用 ShowMapsUpdateUI,這樣下載的地圖可以保持當前。

總結

在這篇文章,我將向您展示如何將應用程式資料添加到地圖控制 Windows Phone 8.1。這包括向地圖添加 XAML 控制項、 資料繫結和繪圖控制項到規模。此外演示了如何將地圖控制項基礎資料離線,所以可以設置地圖控制項內設計供離線使用的應用程式無縫地工作。


KeithPijanowski 是工程師、 企業家、 和業務傢伙他有 20 多年的經驗在軟體行業,致力於初創企業和大公司在經歷了從編寫代碼對商業發展的角色。聯繫到他在 keithpij@msn.comtwitter.com/keithpij

感謝以下的微軟技術專家對本文的審閱:邁克奧馬利
邁克奧馬利是高級專案經理,在微軟的作業系統。他一直在 Mmap-相關開發商微軟三年來的經驗和在生成位置感知應用程式開發提出了每年。