# 添加應用數據至 Windows Phone 8.1 地圖控件
**[Keith Pijanowski](https://msdn.microsoft.com/zh-cn/magazine/ee532098.aspx?sdmr=KeithPijanowski&sdmi=authors)**
**[下載代碼示例](https://msdn.microsoft.com/zh-cn/magazine/msdnmag0115)**
在我一 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**,會意識到你將無法訪問您的代碼隱藏文件中的控件。智能感知將確認您的控件名稱作為有效的變量,但在運行時這些變量將始終為 null,如果你引用它們你會舉出。MapItemControl 通常用于包含用于將對象的集合綁定到地圖控件的數據模板。(這會將討論在本文稍后部分。因此,如果你不綁定到的對象的集合,它是更好地將您的控件添加為地圖控件的子級中所示**圖 1**。
**數據綁定**?中的代碼?**圖 1**?使用數據綁定來設置圖像控件和文本塊的位置屬性。Text 屬性的 TextBlock 還利用數據綁定。要快速查看,位置屬性是類型的附加的屬性 Geopoint。它用來指定在地圖上將放置該控件的位置。NormalizedAnchorPoint 附加屬性允許將微調控件的位置。例如,您可以使用 NormalizedAnchorPoint 屬性來中心位置的控制權或放置控件左上角的位置上。在我第一篇文章中詳細討論了這兩個屬性 ([msdn.microsoft.com/magazine/dn818495](https://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](http://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";
}
~~~

**圖 8 距離尺度添加到地圖控件顯示日落碼頭在佛羅里達州基韋斯特市**
## 下載地圖供脫機使用
地圖可以下載供脫機使用。這是非常方便的應用程序需要提供映射功能,沒有任何形式的互聯網連接設備時,如當用戶正行駛在一個長的公路之間市區或深藏在樹林里徒步旅行。
因為它們占用大量的存儲,不能未經用戶同意以編程方式下載的地圖。用戶必須選擇在每次下載到通過使用一個系統 — —-提供了允許的 UX 需選擇并下載的地圖。這被通過使用靜態類 MapManager,屬于 Windows.Services.Maps 命名空間。此類提供對下載的地圖和更新映射函數。這里所示的 ShowDownloadedMapsUI 函數將啟動內置的地圖應用程序并顯示中顯示的網頁**圖 9**:
~~~
MapManager.ShowDownloadedMapsUI();
~~~

**圖 9 用于下載地圖的 UI**
內置的地圖應用程序名地圖中顯示的網頁**圖 9**?也可以通過點擊下載映射按鈕從設置菜單選項訪問。因為此函數把用戶帶到另一個應用程序 (內置的地圖應用程序),他將不得不手動返回到原始的應用程序。
中顯示的網頁**圖 9**?顯示先前已下載的所有映射。它還包含一個菜單選項,允許您刪除任何先前已下載的映像存儲在設備上需要被釋放或不再需要一張地圖的情況下。
點擊添加 (+) 按鈕啟動地圖選擇向導,顯示一個頁面,允許您指定包含您想要下載的地圖的大陸。一旦選定了一個大洲,將顯示頁,其中顯示在選定的非洲大陸的所有國家。您可以選擇在大陸的所有國家和下載地圖為整個非洲大陸,但這將需要大量的存儲空間。例如,對于美國的所有映射都需要 3.4 GB 的存儲空間。整個大陸的北美洲和中美洲地區將需要更多。
如果您選擇包含多個地區或國家的一個大的國家,你會看到一個頁面,允許您選擇特定區域或國家。您可以通過使用選擇按鈕來選擇多個區域。當指定一個區域時,你會被帶到示的下載頁面**圖 10**。這個頁面還將是否您選擇一個小的國家,沒有任何地區或國家所示。

**圖 10 下載一張地圖**
在下載之前的任何映射,它是一個好主意,以鼓勵使用者通過去設置應用程序并選擇存儲感檢查設備上的可用空間。這將顯示可用空間在設備上,如空間需要被釋放的情況下使用每個應用程序在設備上的存儲空間。在寫這篇文章的時候,沒有 WinRT Api,這使您可以以編程方式確定使用設備上的存儲量或可用存儲量。
它也是一個好的主意來下載地圖雖然連接到不受限制的網絡,無線上網等。這篇文章的代碼示例演示如何檢查當前的網絡連接,并警告用戶,如果他們是在計量的連接上。
## 更新已下載的映像
地圖是偶爾更改或修改。新的道路可能會添加到一個城市,街道名稱可能會改變,有時改變了區域的邊界。因此,應定期更新已下載的映像。MapManager 靜態類包含一個功能叫做 ShowMapsUpdateUI 的更新已下載的映像:
~~~
MapManager.ShowMapsUpdateUI();
~~~
ShowMapsUpdateUI 函數是類似于 ShowDownloadedMapsUI 的功能,因為它具有內置的地圖應用程序用戶。當調用此函數時,所有已下載的映像檢查,看看是否他們需要更新。如果任何先前下載的地圖需要更新,用戶會告訴更新的大小,并給出了選擇取消或繼續執行下載。這相同的功能也是從設置菜單選項的地圖應用程序可用。
如果您的應用程序鼓勵下載地圖,利用 ShowDownloadedMapsUI,它是最佳的做法,也使用 ShowMapsUpdateUI,這樣下載的地圖可以保持當前。
## 總結
在這篇文章,我將向您展示如何將應用程序數據添加到地圖控制 Windows Phone 8.1。這包括向地圖添加 XAML 控件、 數據綁定和繪圖控件到規模。此外演示了如何將地圖控件基礎數據脫機,所以可以設置地圖控件內設計供脫機使用的應用程序無縫地工作。