【IT168专稿】在本系列(两篇)文章中,我将通过一个基本的案例程序向你介绍如何通过在Silverlight 4应用程序中集成Bing Maps Silverlight控件来构建一个时下流行的Mashup型应用程序。
【提示】本文示例开发环境为:
- WINDDOWS XP Professional(SP3);
- .NET 4.0;
- VS2010+Microsoft Silverlight 4 Tools for Visual Studio 2010;
- Bing Maps Silverlight Control SDK。
一、准备工作
(1)创建一个Bing Maps账户与创建Bing Maps键
打开网站http://www.bingmapsportal.com/。请登录或创建一个Windows Live ID账户。在登录成功后,单击左边的“Create or view keys”。随后,在新页面的右方的“Create key”小对话框。随便输入一个应用程序名和程序URL,并选择一个类型,然后单击“Create key”按钮生成你创建本文示例需要的键值(复制下来备后面使用)。在免费的情况下,你可以生成五个键值,如图1所示。
图1. 下创建Bing Maps键的界面快照。
(2)到MSDN网站下载与安装Bing Maps Silverlight Control SDK
图2. 下载Bing Maps Silverlight Control SDK快照。
下载URL是:http://www.microsoft.com/downloads/details.aspx?displaylang=en&familyid=beb29d27-6f0c-494f-b028-1e0e3187e830。
二、创建示例应用程序
启动Visual Studio 2010创建一个基本的Silverlight 4示例工程,命名工程为SL4BingMashup。同时,选择创建一个“Silverlight Application”类型的宿主网站。
(1)引用Bing Maps API程序集
现在,我们来引用Bing Maps API程序集以方便对于地图的控制。
右键单击上面创建的Silverlight示例工程,然后选择“Add Reference…”。在随后的“Add Reference…”对话框中,使用“浏览”导航到路径C:\Program Files\Bing Maps Silverlight Control\V1\Libraries(这是上述SDK的默认安装位置)下。选择添加两个程序集Microsoft.Maps.MapControl.Common.dll和Microsoft.Maps.MapControl.dll。
(2)创建地图
现在,我们已经构建好应用程序框架并添加了必要的程序集引用。接下来,我们就可以创建地图控件了。打开文件MainPage.xaml,输入如下XAML代码:
然后,在上述格子控件中添加两列:
<ColumnDefinition />
<ColumnDefinition Width="200"/>
</Grid.ColumnDefinitions>
现在,我们已经规划好的整个应用程序主界面布局。接下来,我们要添加引用Bing maps的命名空间,如下所示:
现在,我们要添加地图控件。在行的下面,添加如下所示的地图控件(显然,这里的Bing Maps键应当是你前面申请生成的其中之一):
这个地图控件提供了几个重要的属性需要解释。首先,它使用别名bing来引用地图控件对应的命名空间,然后使用此别名来调用这个命名空间内包含的地图控件。这个控件有一个重要属性-CredentialsProvider属性。此属性的值是你前面注册时生成的键值之一。
最后,我们来验证您的代码是否正常运行。结果看起来应该像图3。
图3.调用Bing Map的基本型Silverlight应用程序。
(3)构建一个简单的Airport类
现在,我们要构建一个新类Airport。这个类中能够提供所有美国飞机场中当前状态数据。这个类的代码如下:
{
public string ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public Location Location { get; set; }
}
注意其中的Location属性。此属性的类型定义于命名空间Microsoft.Maps.MapControl中。
(4)加载XML数据—Airports.xml
本示例中所提供的所有美国飞机场简单信息数据(其中仅提供了代码及飞机场名称)包含在一个XML文件Airports.xml中。尽管如此,我们可以通过Bing提供的WCF服务并通过简单的编程取得感兴趣的飞机场有关数据。此文件的部分内容如下:
<Airports>
<Airport id="SEA" name="Seattle-Tacoma International Airport, WA" />
<Airport id="MIA" name="Miami International Airport, FL" />
<Airport id="MCO" name="Orlando International Airport, FL" />
<!—……其他省略-->
</Airports>
(5)添加Bing Maps服务引用
要应用Bing Maps服务,可以右键单击示例工程SL4BingMashup并选择“Add Service References…”。然后,在地址栏中输入如下服务地址URL并点击按钮Go:
http://dev.virtualearth.net/webservices/v1/geocodeservice/geocodeservice.svc
当服务最后加载完成时,你会观察到如图4所示的内容。在本示例中,我把服务名更改为geoservices。
图4. 添加基于Bing支持的WCF服务引用。
三、读取飞机场数据与消费WCF服务
现在,我们已经配置好了WCF服务并且拥有了机场名单。此后,在使用这些数据时,我们必须找到每个机场的位置。
(1)继续修改XAML代码
所以,现在请切换回MainPage.xaml文件,并在地图控件的下部添加如下的XAML代码:
<Button Content="Install" x:Name="btnInstall" Height="25"/>
<ListBox x:Name="lstbAirports" Margin="10,0,0,0">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding ID}" />
<TextBlock Text=" - " />
<TextBlock Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
请特别注意其中添加的按钮控件和ListBox控件。这里,我们把Listbox的DataTemplate模板修改了一下,使之显示形如“ID – Name”格式的数据。至此,XAML代码部分全部构建完毕。
(2)后台代码编程
接下来,我们打开后台代码文件MainPage.xaml.cs添加一个读取文件Airports.xml内容的方法。然后,我们便可以通过Bing提供的WCF地理信息服务Geoservices检索每一个机场的位置信息。
首先,需要添加对于两个重要命名空间Microsoft.Maps.MapControl和System.Xml.Linq的引用。
然后,创建下面两个私有变量:
private geoService.GeocodeRequest _geocodeRequest;
private List<Airport> Airports;
这些变量将帮助我们消费Bing地理信息服务。其中,变量_geoservice是一个针对Bing服务的引用,变量_geocodeRequest十分重要,请参考后面代码。第三个变量Airports是一个泛型List列表,其中将包含当前应用程序运行时相应的所有飞机场数据列表。
至此,创建好了变量。接下来,我们就可以创建一个方法GetAirports以读取文件Airport.xml的内容,并把其中每一个入口数据转换成一个Airport对象以添加进前面创建的Airports列表中。
下面给出方法GetAirports的完整代码:
{
XDocument doc = XDocument.Load("Airports.xml");
_geocodeRequest = new geoService.GeocodeRequest();
_geocodeRequest.Credentials = new Credentials();
_geocodeRequest.Credentials.ApplicationId = ((ApplicationIdCredentialsProvider)myMAP.CredentialsProvider).ApplicationId;
foreach (var item in doc.Elements("Airports").Elements("Airport").ToList())
{
var airport = new Airport();
airport.ID = item.Attributes("id").FirstOrDefault().Value;
airport.Name = item.Attributes("name").FirstOrDefault().Value;
Airports.Add(airport);
Search(airport.ID);
}
}
归纳来看,上面这个方法实现如下功能:
- 创建一个类型XDocument的局部变量,以便通过Linq To XML技术读XML文件内容。
- 创建一个GeocodeRequest类的实例。
- 创建一个Credentials证书类的实例,它将负责加载我们在本文开头提到的证书。
- 修改_geocodeRequest.Credentials.ApplicationId属性值,修改以前面XAML代码myMAP控件提供的ApplicationId属性值。
- 通过一个foreach循环遍历整个airports.xml文件,并为每个机场节点数据,创建一个Airport类的实例,最后将它添加到list类型的变量Airports中。
最后,请注意上面的foreach循环中的最后一句,它调用了另一个方法Search。这个方法负责搜索飞机场位置信息。下面给出这个方法的相应代码:
{
if (_geoservice == null)
{
_geoservice = new geoService.GeocodeServiceClient(
"BasicHttpBinding_IGeocodeService");
_geoservice.GeocodeCompleted += new EventHandler<
geoService.GeocodeCompletedEventArgs>(service_GeocodeCompleted);
}
_geocodeRequest.Query = id;
_geoservice.GeocodeAsync(_geocodeRequest);
}
该方法首先确定一下geoservice服务没有运行其他的实例,以避免不必要的编码及内存消耗。如果条件成立,那么该方法创建服务的一个实例并传递进一个高级参数—BasicHttpBinding_IGeocodeService(有关细节请参考添加服务自动生成的文件Reference.cs及MSDN中的Bing Map SDK)。然后订阅服务的GeocodeCompleted事件。最后,通过调用服务的GeocodeAsync方法并传递进适当的参数启动对于WCF服务的异步调用。
下面,我们继续讨论处理上述异步调用返回结果的代码。
{
if (e.Result.ResponseSummary.StatusCode ==
geoService.ResponseStatusCode.Success)
{
if (e.Result.Results[0].EntityType == "Airport")
{
var airport = Airports.Where(p => p.Name ==
e.Result.Results[0].DisplayName).FirstOrDefault();
airport.Location = e.Result.Results[0].Locations[0];
}
}
}
如果返回条件满足并且调用成功(返回结果为Airport类型),那么我们搜索前面创建的字典以便找到与服务返回中名称一致的飞机场数据。此后,使用最新信息修改对应机场的位置信息。
最后,我们来看一下应用程序整体初始化情况。
{
InitializeComponent();
Airports = new List<Airport>();
GetAirports();
lstbAirports.ItemsSource = Airports; uiElements
}
现在,再次运行应用程序,你会观察到一个类似于图5的结果快照。
图5. 通过Bing提供的WCF地理信息服务启动的应用程序快照。
三、小结
在本篇中,我们讨论了创建一个操作Bing Maps Silverlight地图控件的基本应用的前期工作,并且能够初步使用Bing提供的WCF地理信息服务。在下一篇中,我们将继续探讨Bing服务编程知识并进一步扩展应用程序使之支持浏览器外运行功能。