Windows phone 8 学习笔记(8) 定位地图导航
Windows phone 8 已经不使用自家的bing地图,新地图控件可以指定制图模式、视图等。bing地图的定位误差比较大,在模拟器中测试新地图貌似比较理想。本节主要讲解下位置服务以及新地图控件的使用。
一、定位服务
通过手机定位服务可以开发利用手机地理位置的应用。我们可以通过应用监视手机行踪,配合地图使用可以用于导航等。定位服务可以及时取得手机地理位置,也可以持续跟踪手机移动,还可以在后台运行。
1. 立即获取当前位置
我们可以通过一次操作获取当前位置,下面的代码演示了实现的方法。
[C#]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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#]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | 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]1 2 3 4 5 | < DefaultTask Name="_default" NavigationPage="MainPage.xaml"> < BackgroundExecution > < ExecutionType Name="LocationTracking" /> </ BackgroundExecution > </ DefaultTask > |
然后我们需要注册RunningInBackground事件,打开App.xaml添加事件Application_RunningInBackground,代码如下:
[XAML]1 2 3 4 5 | <!--处理应用程序的生存期事件所需的对象--> < 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#]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | //确定应用是否在后台运行 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#]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 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]1 2 | xmlns:maps="clr-namespace:Microsoft.Phone.Maps.Controls;assembly=Microsoft.Phone.Maps" |
1.引入地图控件
在XAML中添加如下代码即可引入控件。我们看到Center就是指当前地图中心点的经纬度;ZoomLevel就是缩放级别; LandmarksEnabled 属性设置为 true 以在 Map 控件上显示地标; PedestrianFeaturesEnabled 设置为 true,以显示步行街构造。
[XAML]1 2 3 4 5 6 7 8 9 | <!--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#]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | //切换制图模式 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#]1 2 3 4 5 6 7 | //切换颜色模式 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#]1 2 3 4 5 | private void Button_Click_1( object sender, RoutedEventArgs e) { //以抛物线的方式,把视角定位到光谷软件园中心湖上空。 MyMap.SetView( new GeoCoordinate(30.476724, 114.406563), 16, MapAnimationKind.Parabolic); } |
5.定位我的位置并标记
把地图定位到我的当前位置。这个时候就需要借助定位的功能,通过定位功能获取到的经纬度实例类型不一样,需要预先做一个转换。转换类CoordinateConverter如下。
[C#]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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#]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | //添加其他控件到地图,标识我的当前位置 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]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | < 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#]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | 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(); } } } |
出处:[http://www.cnblogs.com/lipan/]
版权声明:本文的版权归作者与博客园共有。转载时须注明原文出处以及作者,并保留原文指向型链接,不得更改原文内容。否则作者将保留追究其法律责任。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架