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();
            }
        }

    }

 

作者:[ Lipan]
出處:[ http://www.cnblogs.com/lipan/]
版權聲明:本文的版權歸作者與博客園共有。轉載時須注明原文出處以及作者,並保留原文指向型鏈接,不得更改原文內容。否則作者將保留追究其法律責任。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM