標籤:des blog http color 使用 os strong io
Windows phone 8 已經不使用自家的bing地圖,新地圖控制項可以指定製圖模式、視圖等。bing地圖的定位誤差比較大,在模擬器中測試新地圖貌似比較理想。本節主要講解下位置服務以及新地圖控制項的使用。
快速導航:
一、定位服務
二、地圖和導航 一、定位服務
通過手機定位服務可以開發利用手機地理位置的應用。我們可以通過應用監視手機行蹤,配合地圖使用可以用於導航等。定位服務可以及時取得手機地理位置,也可以持續跟蹤手機移動,還可以在後台運行。 1. 立即擷取當前位置
我們可以通過一次操作擷取當前位置,下面的代碼示範了實現的方法。
[C#]
private
async
void
OneShotLocation_Click(
object
sender, RoutedEventArgs e)
{
//地理位置訪問服務
Geolocator geolocator =
new
Geolocator();
//定義精度,米為單位
geolocator.DesiredAccuracyInMeters = 1;
try
{
//開始擷取當前位置的經緯度
Geoposition geoposition = await geolocator.GetGeopositionAsync();
LatitudeTextBlock.Text =
"經度:"
+ geoposition.Coordinate.Latitude.ToString(
"0.00"
);
LongitudeTextBlock.Text =
"緯度:"
+ geoposition.Coordinate.Longitude.ToString(
"0.00"
);
}
catch
(Exception ex)
{
if
((
uint
)ex.HResult == 0x80004004)
{
StatusTextBlock.Text =
"系統設定關閉了位置服務."
;
}
}
}
2. 持續跟蹤位置資訊
如果開啟持續跟蹤手機位置,當手機移動距離超出設定距離時,就會觸發位置改變事件,這個時候我們就可以通過環境資訊計算出手機的行動軌跡,速度方向等。下面示範了如何持續跟蹤。
[C#]
Geolocator geolocator =
null
;
bool
tracking =
false
;
private
void
TrackLocation_Click(
object
sender, RoutedEventArgs e)
{
if
(!tracking)
{
//地理位置訪問服務
geolocator =
new
Geolocator();
//精度層級
geolocator.DesiredAccuracy = PositionAccuracy.High;
//超過多少米引發位置改變事件
geolocator.MovementThreshold = 100;
//功能狀態改變時
geolocator.StatusChanged += geolocator_StatusChanged;
//位置改變時
geolocator.PositionChanged += geolocator_PositionChanged;
tracking =
true
;
TrackLocationButton.Content =
"停止跟蹤"
;
}
else
{
geolocator.PositionChanged -= geolocator_PositionChanged;
geolocator.StatusChanged -= geolocator_StatusChanged;
geolocator =
null
;
tracking =
false
;
TrackLocationButton.Content =
"跟蹤位置"
;
StatusTextBlock.Text =
"停止"
;
}
}
void
geolocator_StatusChanged(Geolocator sender, StatusChangedEventArgs args)
{
string
status =
""
;
switch
(args.Status)
{
case
PositionStatus.Disabled:
status =
"位置服務設定被禁用"
;
break
;
case
PositionStatus.Initializing:
status =
"正在初始化"
;
break
;
case
PositionStatus.NoData:
status =
"無資料"
;
break
;
case
PositionStatus.Ready:
status =
"已準備"
;
break
;
case
PositionStatus.NotAvailable:
status =
"無法使用"
;
break
;
case
PositionStatus.NotInitialized:
break
;
}
Dispatcher.BeginInvoke(() =>
{
StatusTextBlock.Text = status;
});
}
void
geolocator_PositionChanged(Geolocator sender, PositionChangedEventArgs args)
{
Dispatcher.BeginInvoke(() =>
{
LatitudeTextBlock.Text =
"經度:"
+ args.Position.Coordinate.Latitude.ToString(
"0.00"
);
LongitudeTextBlock.Text =
"緯度:"
+ args.Position.Coordinate.Longitude.ToString(
"0.00"
);
});
}
3. 在後台持續跟蹤
位置跟蹤可以作為服務在後台運行,這個時候我們不需要更新UI,為了使我們的應用可以作為服務運行,我們需要右鍵開啟資訊清單檔,選擇用XML文字編輯器的方式,替換DefaultTask節點為如下資訊:
[XML]
<DefaultTask Name="_default" NavigationPage="MainPage.xaml"> <BackgroundExecution> <ExecutionType Name="LocationTracking" /> </BackgroundExecution> </DefaultTask>
然後我們需要註冊RunningInBackground事件,開啟App.xaml添加事件Application_RunningInBackground,代碼如下:
[XAML]
<!--處理應用程式的生存期事件所需的對象--> <shell:PhoneApplicationService Launching="Application_Launching" Closing="Application_Closing" Activated="Application_Activated" Deactivated="Application_Deactivated" RunningInBackground="Application_RunningInBackground"/>
在App.xaml.cs中添加靜態變數RunningInBackground和Geolocator,當Application_RunningInBackground事件時RunningInBackground為true,當Application_Activated事件時,RunningInBackground為false。代碼如下:
[C#]
//確定應用是否在後台運行public static bool RunningInBackground { get; set; }//提供對當前地理位置的訪問public static Geolocator Geolocator { get; set; }// 啟用應用程式(置於前台)時執行的代碼// 此代碼在初次開機應用程式時不執行private void Application_Activated(object sender, ActivatedEventArgs e){ RunningInBackground = false;}private void Application_RunningInBackground(object sender, RunningInBackgroundEventArgs args){ RunningInBackground = true;}
在mainpage中添加如下代碼:
[C#]
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e){ if (App.Geolocator == null) { App.Geolocator = new Geolocator(); App.Geolocator.DesiredAccuracy = PositionAccuracy.High; App.Geolocator.MovementThreshold = 100; App.Geolocator.PositionChanged += geolocator_PositionChanged; }}void geolocator_PositionChanged(Geolocator sender, PositionChangedEventArgs args){ if (!App.RunningInBackground) { Dispatcher.BeginInvoke(() => { LatitudeTextBlock.Text = "經度:" + args.Position.Coordinate.Latitude.ToString("0.00"); LongitudeTextBlock.Text = "緯度:" + args.Position.Coordinate.Longitude.ToString("0.00"); }); } else { Microsoft.Phone.Shell.ShellToast toast = new Microsoft.Phone.Shell.ShellToast(); toast.Content = args.Position.Coordinate.Latitude.ToString("0.00") + "," + args.Position.Coordinate.Longitude.ToString("0.00"); toast.Title = "位置:"; toast.NavigationUri = new Uri("/Page1.xaml", UriKind.Relative); toast.Show(); }}
二、地圖和導航
要用到新地圖控制項,需要先註冊,在phone:PhoneApplicationPage註冊標識。
[XAML]
xmlns:maps="clr-namespace:Microsoft.Phone.Maps.Controls;assembly=Microsoft.Phone.Maps"
1.引入地圖控制項
在XAML中添加如下代碼即可引入控制項。我們看到Center就是指當前地圖中心點的經緯度;ZoomLevel就是縮放層級; LandmarksEnabled 屬性設定為 true 以在 Map 控制項上顯示地標; PedestrianFeaturesEnabled 設定為 true,以顯示步行街構造。
[XAML]
<!--ContentPanel - 在此處放置其他內容--> <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <!--地圖控制項--> <maps:Map x:Name="MyMap" Center="30.5473, 114.2922" ZoomLevel="10" LandmarksEnabled="true" PedestrianFeaturesEnabled="true" /> <Button Foreground="Red" Content="指定位置" HorizontalAlignment="Left" Margin="295,530,0,0" VerticalAlignment="Top" Click="Button_Click_1" Width="151"/> <Button Foreground="Red" Content="製圖模式" HorizontalAlignment="Left" Margin="10,530,0,0" VerticalAlignment="Top" Click="Button_Click_2"/> <Button Foreground="Red" Content="顏色模式" HorizontalAlignment="Left" Margin="134,530,0,0" VerticalAlignment="Top" Click="Button_Click_3"/> <Button Foreground="Red" Content="我的位置" HorizontalAlignment="Left" Margin="10,602,0,0" VerticalAlignment="Top" Click="Button_Click_4"/> </Grid>
2.設定製圖模式
在製圖模式中有四個選項,分別如下:
Road:顯示正常的預設二維地圖。
Aerial:顯示航測圖。
Hybrid:顯示與道路和標籤重疊的地圖的“航測”視圖。
Terrain:為顯示的高地和水域構造(例如高山和河流)顯示自然地形映像。
下面看看如何切換。
[C#]
//切換製圖模式private void Button_Click_2(object sender, RoutedEventArgs e){ switch (MyMap.CartographicMode) { case MapCartographicMode.Aerial: MyMap.CartographicMode = MapCartographicMode.Hybrid; break; case MapCartographicMode.Hybrid: MyMap.CartographicMode = MapCartographicMode.Road; break; case MapCartographicMode.Road: MyMap.CartographicMode = MapCartographicMode.Terrain; break; case MapCartographicMode.Terrain: MyMap.CartographicMode = MapCartographicMode.Aerial; break; }}
3.設定顏色模式
顏色分為明和暗兩種,我們看看如何?。
[C#]
//切換顏色模式private void Button_Click_3(object sender, RoutedEventArgs e){ if (MyMap.ColorMode == MapColorMode.Light) MyMap.ColorMode = MapColorMode.Dark; else MyMap.ColorMode = MapColorMode.Light;}
4.指定新視角位置
我們可以通過編程方式切換視角位置到新的經緯度,並可以指定切換時的過渡效果,這裡指定的是拋物線的方式。
[C#]
private void Button_Click_1(object sender, RoutedEventArgs e){ //以拋物線的方式,把視角定位到光穀軟體園中心湖上空。 MyMap.SetView(new GeoCoordinate(30.476724, 114.406563), 16, MapAnimationKind.Parabolic);}
5.定位我的位置並標記
把地圖定位到我的當前位置。這個時候就需要藉助定位的功能,通過定位功能擷取到的經緯度執行個體類型不一樣,需要預先做一個轉換。轉換類CoordinateConverter如下。
[C#]
public static class CoordinateConverter{ /// <summary> /// 把定位位置轉換為地圖位置 /// </summary> /// <param name="geocoordinate"></param> /// <returns></returns> public static GeoCoordinate ConvertGeocoordinate(Geocoordinate geocoordinate) { return new GeoCoordinate ( geocoordinate.Latitude, geocoordinate.Longitude, geocoordinate.Altitude ?? Double.NaN, geocoordinate.Accuracy, geocoordinate.AltitudeAccuracy ?? Double.NaN, geocoordinate.Speed ?? Double.NaN, geocoordinate.Heading ?? Double.NaN ); }}
然後,我們需要在地圖上畫一個小正方形標記我的當前位置,並把地圖定位到這裡。
[C#]
//添加其他控制項到地圖,標識我的當前位置private async void Button_Click_4(object sender, RoutedEventArgs e){ //擷取我的地理位置 Geolocator myGeolocator = new Geolocator(); //精度 myGeolocator.DesiredAccuracyInMeters = 1; Geoposition myGeoposition = await myGeolocator.GetGeopositionAsync(); Geocoordinate myGeocoordinate = myGeoposition.Coordinate; //轉換經緯度GeoCoordinate GeoCoordinate myGeoCoordinate = CoordinateConverter.ConvertGeocoordinate(myGeocoordinate); //MessageBox.Show(myGeoCoordinate.ToString()); //定位地圖到我的位置 MyMap.SetView(myGeoCoordinate, 16, MapAnimationKind.Parabolic); //畫一個正方形,然後渲染在地圖的我的當前位置上 Rectangle MyRectangle = new Rectangle(); MyRectangle.Fill = new SolidColorBrush(Colors.Black); MyRectangle.Height = 20; MyRectangle.Width = 20; MapOverlay MyOverlay = new MapOverlay(); MyOverlay.Content = MyRectangle; MyOverlay.GeoCoordinate = myGeoCoordinate; MyOverlay.PositionOrigin = new Point(0, 0.5); MapLayer MyLayer = new MapLayer(); MyLayer.Add(MyOverlay); MyMap.Layers.Add(MyLayer);}
6.擷取行車路線
我們還可以通過定位和地圖實現導航的功能,下面示範了,從我的當前位置(光穀軟體園)到指定的位置(光穀創業街)如何行車。
[XAML]
<phone:PhoneApplicationPage.Resources> <DataTemplate x:Key="RouteListTemplate"> <TextBlock Text="{Binding}" FontSize="{StaticResource PhoneFontSizeMedium}" Margin="5,5,0,0"/> </DataTemplate> </phone:PhoneApplicationPage.Resources> <!--LayoutRoot 是包含所有頁面內容的根網格--> <Grid x:Name="LayoutRoot" Background="Transparent"> <Grid.RowDefinitions> <RowDefinition Height="auto"/> <RowDefinition Height="*"/> <RowDefinition Height="auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <TextBlock Text="地圖導航" Grid.Row="0" FontSize="{StaticResource PhoneFontSizeLarge}" Margin="0,0,0,20"/> <maps:Map x:Name="MyMap" Grid.Row="1" Center="30.476724, 114.406563" ZoomLevel="13"/> <TextBlock Text="駕車路線" Grid.Row="2" FontSize="{StaticResource PhoneFontSizeLarge}" Margin="0,10,0,20"/> <phone:LongListSelector x:Name="RouteLLS" Grid.Row="3" Background="Transparent" ItemTemplate="{StaticResource RouteListTemplate}" LayoutMode="List" IsGroupingEnabled="False"/> </Grid>
[C#]
public partial class Page1 : PhoneApplicationPage { public Page1() { InitializeComponent(); this.GetCoordinates(); } RouteQuery MyQuery = null; GeocodeQuery Mygeocodequery = null; List<GeoCoordinate> MyCoordinates = new List<GeoCoordinate>(); private async void GetCoordinates() { Geolocator MyGeolocator = new Geolocator(); MyGeolocator.DesiredAccuracyInMeters = 5; Geoposition MyGeoPosition = null; try { MyGeoPosition = await MyGeolocator.GetGeopositionAsync(TimeSpan.FromMinutes(1), TimeSpan.FromSeconds(10)); } catch (UnauthorizedAccessException) { MessageBox.Show("系統設定已關閉位置服務。"); } catch (Exception ex) { } MyCoordinates.Add(new GeoCoordinate(MyGeoPosition.Coordinate.Latitude, MyGeoPosition.Coordinate.Longitude)); Mygeocodequery = new GeocodeQuery(); Mygeocodequery.SearchTerm = "光穀創業街"; Mygeocodequery.GeoCoordinate = new GeoCoordinate(MyGeoPosition.Coordinate.Latitude, MyGeoPosition.Coordinate.Longitude); Mygeocodequery.QueryCompleted += Mygeocodequery_QueryCompleted; Mygeocodequery.QueryAsync(); } void Mygeocodequery_QueryCompleted(object sender, QueryCompletedEventArgs<IList<MapLocation>> e) { if (e.Error == null) { MyQuery = new RouteQuery(); MyCoordinates.Add(e.Result[0].GeoCoordinate); MyQuery.Waypoints = MyCoordinates; MyQuery.QueryCompleted += MyQuery_QueryCompleted; MyQuery.QueryAsync(); Mygeocodequery.Dispose(); } } void MyQuery_QueryCompleted(object sender, QueryCompletedEventArgs<Route> e) { if (e.Error == null) { //擷取具體的行程路線 Route MyRoute = e.Result; MapRoute MyMapRoute = new MapRoute(MyRoute); MyMap.AddRoute(MyMapRoute); List<string> RouteList = new List<string>(); foreach (RouteLeg leg in MyRoute.Legs) { foreach (RouteManeuver maneuver in leg.Maneuvers) { RouteList.Add(maneuver.InstructionText); } } RouteLLS.ItemsSource = RouteList; MyQuery.Dispose(); } } }