zoukankan      html  css  js  c++  java
  • Windows phone 8 学习笔记(8) 定位地图导航(转)

    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();
                }
            }
    
        }
  • 相关阅读:
    JS 、JQ 获取宽高总结 & JS中getBoundingClientRect的作用及兼容方案
    JS与JQ 获取页面元素值的方法和差异对比
    ES6
    移动端:active伪类无效的解决方法
    JavaScript中valueOf函数与toString方法
    Reverse Words in a String -- LeetCode
    Count Primes -- LeetCodes (primality test)
    Maximum Size Subarray Sum Equals k -- LeetCode
    Subsets II -- LeetCode
    Maximum Product of Word Lengths -- LeetCode
  • 原文地址:https://www.cnblogs.com/jx270/p/3886407.html
Copyright © 2011-2022 走看看