Windows Phone中Map控件由浅及深

鄙人所在的OMG团队在高级软件工程课程团队项目,负责Microsoft的Academic Search在手机WP7.1上客户端的开发。现已进入十天的beta版本开发阶段。这两天用到了Map控件,我想结合自己dev的经历,对Map控件稍作介绍。

〖PS:我们是来自中国科大各个专业(数学、EE、CS)的大四学生,六个人,欢迎各位看官来我们的团队技术博客指点一二:http://www.cnblogs.com/OMG-Team/

 

Map控件,是基于Microsoft的Bing map的地图控件,在WP7能很好的使用bing map实现地图的呈现,缩放,标注和定位等功能。

首先,介绍一下Map控件的简单应用吧。

在使用Map控件之前,我们必须先注册地图获得一个Register Key才能够使用bing map,注册地址:https://www.bingmapsportal.com 。新建一个Sliverlight for Windows Phone的工程,就可以开始练习使用Map控件了。在xaml里添加一个地图控件

在.cs文件里添加register key的代码(或者不使用Binding直接写在xaml中也行)

 

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">  
<my:Map Height="623" HorizontalAlignment="Left"
CredentialsProvider
="{Binding CredentialsProvider}"
Margin
="12,-22,0,0" Name="map1"

VerticalAlignment
="Top" Width="425"/>
</Grid>



note:应该添加一个namespace:

 1 using Microsoft.Phone.Controls.Maps; 
2
3 namespace MapExample
4 {
5 public partial class MainPage : PhoneApplicationPage
6 {
7 const String BingMapsId = "Al7xKT8k0tvRNSCTc0uQs6AM1k-gREOdyigcbbbL4z932ynL42ySQuht1Ur6hpLI";
8 private readonly CredentialsProvider credentialsProvider = new ApplicationIdCredentialsProvider(BingMapsId);
9 public CredentialsProvider CredentialsProvider
10 {
11 get { return credentialsProvider; }
12 }
13 // Constructor
14 public MainPage()
15 {
16 InitializeComponent();
17 }
18 }
19 }



这样就可以运行一个最基本的map控件了。

下面,我们看看如何设置map的中心点以及Zoomlevel以及显示模式。

这个很简单只需要改变Center、 Zoomlevel和Map.Mode这几个属性的值,同样可以在xaml直接设置,或者在.cs文件里设置,当然,更高级点的用法就是对Center,zoomlevel等进行Binding了。

Map控件还有很多其他的属性,比如ZoomBarVisibility,ScaleVisibility,LogoVisibility等,这些都可以简单的进行设置或者通过Binding技术实现动态的属性值的改变。
然而,Map控件还提供添加标注,添加图片,绘制多边形,多边线等功能。

下面讲讲如何添加一个标记吧。

首先,我们可以在MainPage()里建立并初始化一个标记( 记得添加namespace: using System.Device.Location; )

1 Pushpin pin = new Pushpin(); 
2 pin.Location = new GeoCoordinate(30, 120);
3 pin.Background = new SolidColorBrush(Colors.Black);
4 pin.Content = "Example";
5 pin.Height = 40;
6 pin.Width = 80;
7 map1.Children.Add(pin); // 一定要记得添加到map1这个控件中哦~



对于多边线,我们用到的是Polyline这样一个类,多边形的绘制使用Polygon这个类,插入图片使用MapLayer类,它们的使用跟Pushpin这个类异曲同工。

以上就是一些简单的应用,那么来点实际点的。

我在开发过程中需要使用Map控件实现动态定位,找到自己的所在位置以及某个会议要举行的位置,并在切换过程中在地图中标注出相应的位置,并支持WP7.1的多点触控进行Zoomin和Zoomout。

这需要写一个page,我把它叫做MapPage,然后它的入口接收在页面Navigate时候传过来的三个值,一个是会议举行地点的经度,一个是纬度,还有一个是label,显示在标注上的文字。下面给出源代码仅供参考。

创建一个MapPage,xaml文件如下:

<phone:PhoneApplicationPage x:Class="Client.MapPage"
xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone
="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell
="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d
="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc
="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:System
="clr-namespace:System;assembly=mscorlib"
FontFamily
="{StaticResource PhoneFontFamilyNormal}"
FontSize
="{StaticResource PhoneFontSizeNormal}"
Foreground
="{StaticResource MyPhoneForegroundBrush}"
SupportedOrientations
="Portrait" Orientation="Portrait"
mc:Ignorable
="d" d:DesignWidth="480" d:DesignHeight="728"
shell:SystemTray.IsVisible
="False"
xmlns:my
="clr-namespace:Microsoft.Phone.Controls.Maps;assembly=Microsoft.Phone.Controls.Maps"
>

<Canvas x:Name="LayoutRoot">

<!-- Map View -->
<Border x:Name="Mapw"
Height
="768" Width="480">
<my:Map Name="Map"
CredentialsProvider
="{Binding CredentialsProvider}"
CopyrightVisibility
="Collapsed"
LogoVisibility
="Collapsed"
ZoomLevel
="{Binding Zoom, Mode=TwoWay}"
Center
="{Binding Center, Mode=TwoWay}"
>
<my:Map.Mode>
<my:RoadMode />
</my:Map.Mode>

<my:MapItemsControl x:Name="mapControl"/>
</my:Map>

<!-- TODO : Add map control -->

</Border>

</Canvas>

<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True" IsMenuEnabled="False">
<shell:ApplicationBarIconButton IconUri="/Images/appbar.location.rest.png" Text="current" Click="CurrentLocation_Click"/>
<shell:ApplicationBarIconButton IconUri="/Images/appbar.next.rest.png" Text="venue" Click="VenueLocation_Click"/>
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>


</phone:PhoneApplicationPage>

 

在MapPage.cs文件里完成相应的处理:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Controls.Maps;
using System.Device.Location;
using System.ComponentModel;
using Microsoft.Phone.Controls.Maps.Core;

namespace Client
{
public partial class MapPage : PhoneApplicationPage, INotifyPropertyChanged
{
public MapPage()
{
this.Loaded += new RoutedEventHandler(MapPage_Loaded);
InitializeComponent();
InitializeDefaults();

DataContext = this;
}

private readonly CredentialsProvider credentialsProvider = new ApplicationIdCredentialsProvider(AcademicSearch.App.BingMapsId);
public CredentialsProvider CredentialsProvider
{
get { return credentialsProvider; }
}

private MapLayer pushpinLayer;
private string pushpinLabel;
private Pushpin locationMark;
void MapPage_Loaded(object sender, RoutedEventArgs e)
{
NotifyPropertyChanged("Zoom");
NotifyPropertyChanged("Center");
pushpinLayer = new MapLayer();
Map.Children.Add(pushpinLayer);
pushpinLayer.AddChild(
new Pushpin() {Content =new Border() { Child = new TextBlock() { Text = pushpinLabel },
                            Background=new SolidColorBrush(Colors.Black)}},
Center);
locationMark = new Pushpin() { Content = new Border() { Child = new TextBlock() { Text = "You Are Here!" },
                            Background = new SolidColorBrush(Colors.Black) } };
pushpinLayer.AddChild(locationMark, new GeoCoordinate(0, 0));
}

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
string longitudeStr;
string latitudeStr;
if (NavigationContext.QueryString.TryGetValue("longitude", out longitudeStr) && NavigationContext.QueryString.TryGetValue("latitude", out latitudeStr))
{
double latitude;
double longitude;
if (Double.TryParse(latitudeStr, out latitude) && Double.TryParse(longitudeStr, out longitude))
{
Center = new GeoCoordinate(latitude, longitude);
Venue = new GeoCoordinate(latitude, longitude);
Zoom = DefaultZoomLevel;
}
string label;
if (NavigationContext.QueryString.TryGetValue("label", out label))
{
pushpinLabel = label;
}
else
{
pushpinLabel = "";
}
}
}

public void AddPushpin(GeoCoordinate location)
{
Pushpin pushpin = new Pushpin();
pushpin.Content = "Test";
pushpinLayer.AddChild(pushpin, location);
}

///<summary>
/// Gets or sets the map zoom level.
///</summary>
private const double DefaultZoomLevel = 17.0;
private const double MaxZoomLevel = 21.0;
private const double MinZoomLevel = 1.0;

private double _zoom = DefaultZoomLevel;
public double Zoom
{
get { return _zoom; }
set
{
var coercedZoom = Math.Max(MinZoomLevel, Math.Min(MaxZoomLevel, value));
if (_zoom != coercedZoom)
{
_zoom = value;
NotifyPropertyChanged("Zoom");
}
}
}

private GeoCoordinateWatcher loc = null;

private void CurrentLocation_Click(object sender, EventArgs e)
{
//Zoom += 1;
if (loc == null)
{
loc = new GeoCoordinateWatcher(GeoPositionAccuracy.Default);
loc.StatusChanged += loc_StatusChanged;
}
if (loc.Status == GeoPositionStatus.Disabled)
{
loc.StatusChanged -= loc_StatusChanged;
MessageBox.Show("Location services must be enabled on your phone.");
return;
}
loc.Start();
}

void loc_StatusChanged(object sender, GeoPositionStatusChangedEventArgs e)
{

if (e.Status == GeoPositionStatus.Ready)
{
locationMark.Location = loc.Position.Location;
Map.SetView(loc.Position.Location, 17.0);
loc.Stop();
}
}

private void VenueLocation_Click(object sender, EventArgs e)
{
Map.SetView(Venue, 17.0);
}

private GeoCoordinate _center;
public GeoCoordinate Center
{
get { return _center; }
set
{
if (_center != value)
{
_center = value;
NotifyPropertyChanged("Center");
}
}
}

private GeoCoordinate Venue;

public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}

public bool HasDirections
{
get
{
// TODO : Return true only if has directions.

return true;
}
}


#region Tasks

private void InitializeDefaults()
{
// TODO : Initialize default properties.
}

private void ChangeMapMode()
{
// TODO : Change map view mode.
}

private void IncreaseZoomLevel()
{
// TODO : Increases zoom level.
}

private void DecreaseZoomLevel()
{
// TODO : Decreases zoom level.
}

private void CenterLocation()
{
// TODO : Center current location.
}

private void CenterPushpinsPopup(Point touchPoint)
{
// TODO : Center pushpins popup to the touch point.
}

private void CreateNewPushpin(object selectedItem, Point point)
{
// TODO : Create a new pushpin.
}

private void CalculateRoute()
{
// TODO : Calculate a route.
}

#endregion

}
}

 

 

MSRA-USTC Class

OMG team

posted @ 2011-11-18 10:22  OMG! 日记  阅读(3283)  评论(4编辑  收藏  举报