本文内容:GraphicsLayer,FeatureLayer,自定义地图符号。
我们的应用场景是对超市数据进行展示,查询和分析,因此第一步当然是要将超市显示在地图之上。如所有的GIS软件一样,要将数据加载到地图里面,需要图层的概念,这里我们也需要合适的图层,将超市数据加载进来。
先看一下ArcGIS API for Windows Phone/Silverlight/WPF中的主要图层类型。
Layer
|–TiledMapServiceLayer
| |–ArcGISTiledMapServiceLayer
|–DynamicLayer
| |–DynamicMapServiceLayer
| |–ArcGISDynamicMapServiceLayer
| |–ArcGISImageServiceLayer
| |–GPResultImageLayer
|–GraphicsLayer
| |–FeatureLayer
|–ElementLayer
Layer最基本的基类,常用的几种图层类型我已经用红色标记出来了。前两种ArcGISTiledMapServiceLayer和ArcGISDynamicMapServiceLayer分别用于加载ArcGIS Server发布的缓存地图服务和动态地图服务,这个在上一节中已经说过。再来看一下中间的GraphicsLayer和FeatureLayer,可以说这是API中最常用的两种图层,大部分的程序功能都要基于它们来完成。
GraphicsLayer是保留在内存中的一种图层(与ArcMap、ArcGIS Engine、ArcGIS Server ADF程序中的相应概念类似),顾名思义是很多Graphic的集合,而所有与用户交互的内容通常都用Graphic来显示。比如多边形查询中用户画出的多边形,属性/空间查询结果中的所有要素等内容,都是Graphic。可以说,除了地图本身,基本上看到的所有与地理位置有关的东西都可以用Graphic来表示。Graphic对象有3个重要的属性:Geometry,Symbol和Attributes。Geometry代表了一个Graphic的几何形状(可疑是点、线、面任意一种)或地理位置,而Symbol则表示Graphic的呈现样子,比如颜色、效果,同时有了这两个属性(缺一不可),Graphic就可以显示到地图上了。而Attributes是键值对集合,可在里面存储任意类型的对象,比如一个要素的属性信息。
FeatureLayer继承自GraphicsLayer,它与后者的区别是,GraphicsLayer中的Graphic都是人为创建出来的,而FeatureLayer中的Graphic都是从ArcGIS Server发布的服务中读取出来的,因此FeatureLayer比GraphicsLayer多了一个URL属性。这个URL通常指向一个ArcGIS Server发布的,MapService或FeatureService的子图层(对应一个FeatureClass)。FeatureLayer有了这个URL后,就可以读取出该服务对应子图层里的所有要素内容,因此FeatureLayer里Graphic的Geometry属性会自动被FeatureClass的Shape字段填充,而Graphic的Attributes字段则会根据要求,被FeatureClass中的属性信息所填充。如果发布服务的服务器是ArcGIS Server 10版本,则Graphic的Symbol属性会自动被服务的DrawingInfo信息填充。另外,FeatureLayer是客户端API中对FeatureService的唯一载体,这是它另一个非常重要的作用(也是主要作用),以后的文章中会提到。
ArcGIS API for Windows Phone/Silverlight/WPF/Javascript/Flex/iOS/Android都是基于ArcGIS Server所发布的REST服务,所以,在开始之前,我们需要将超市数据用ArcGIS Server发布成MapService。这个过程不属于本文要讨论的内容,不熟悉的同学可自己查阅相关资料。超市图层的属性表如下,前面是每个店面的基本信息,后面是该月每天的营业额信息:
超市的ShapeFile在这,点我下载。在我本机上发布出来的地址是:http://localhost/ArcGIS/rest/services/supermarket/MapServer/0。
现在打开上一节我们完成的HelloMap程序,来继续改造之。底图服务我们依旧使用ArcGIS Online提供的StreetMap数据http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer,然后我们在Map控件中加入一个FeatureLayer,其URL属性指向发布在本机的超市地图服务。由于我们的数据范围仅限于北京市附近,因此我们可以利用Map的Extent属性指定地图的初始范围,代码现在看起来是这样的:
1: <esri:Map x:Name="map1" Extent="12926244,4840437,12982108,4878585">
2: <esri:Map.Layers>
3: <esri:ArcGISTiledMapServiceLayer ID="BaseMap" Url="http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer" />
4: <esri:FeatureLayer ID="BusinessLayer"
5: Url="http://localhost/arcgis/rest/services/supermarket/MapServer/0"
6: OutFields="*" />
7: </esri:Map.Layers>
8: </esri:Map>
其中FeatureLayer的OutFields属性代表从服务器端返回的属性字段,这里“*”表示返回所有属性字段,也就是我们的Graphic对象的Attributes里自动填充了超市的所有属性值。
需要注意,在xaml代码中,最靠上的图层在显示时会出现在Map控件的最底端,如图:
Silverlight中,可以将常用的任何资源保存到Resource集合中,以便重复利用。因此我们将两个服务地址保存到App.xaml文件的ResourceDictionary中(可在所有页面中直接引用):
1: <Application
2: x:Class="esridemo.App"
3: xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
4: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
5: xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
6: xmlns:esri="clr-namespace:ESRI.ArcGIS.Client;assembly=ESRI.ArcGIS.Client"
7: xmlns:sys="clr-namespace:System;assembly=mscorlib"
8: xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone">
9:
10: <!--Application Resources-->
11: <Application.Resources>
12: <sys:String x:Key="BaseMap">http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer</sys:String>
13: <sys:String x:Key="BusinessLayer">http://localhost/arcgis/rest/services/supermarket/MapServer/0</sys:String>
14: </Application.Resources>
15:
16: <Application.ApplicationLifetimeObjects>
17: <!--Required object that handles lifetime events for the application-->
18: <shell:PhoneApplicationService
19: Launching="Application_Launching" Closing="Application_Closing"
20: Activated="Application_Activated" Deactivated="Application_Deactivated"/>
21: </Application.ApplicationLifetimeObjects>
22:
23: </Application>
将MainPage.xaml中的代码改写成:
1: <esri:Map x:Name="map1" Extent="12926244,4840437,12982108,4878585">
2: <esri:Map.Layers>
3: <esri:ArcGISTiledMapServiceLayer ID="BaseMap" Url="{StaticResource BaseMap}" />
4: <esri:FeatureLayer ID="BusinessLayer"
5: Url="{StaticResource BusinessLayer}"
6: OutFields="*" />
7: </esri:Map.Layers>
8: </esri:Map>
运行一下
可以看到,超市已经显示在地图上面了。但超市的符号依然是ArcMap配置地图文档时的默认值,这里我们来利用FeatureLayer的FeatureSymbol属性,改变一下超市的地图符号。
在App.xaml文件的资源中,添加一个MarkerSymbol类型的超市符号:
1: <esriSymbols:MarkerSymbol x:Key="SuperMarket">
2: <esriSymbols:MarkerSymbol.ControlTemplate>
3: <ControlTemplate>
4: <Canvas>
5: <VisualStateManager.VisualStateGroups>
6: <VisualStateGroup x:Name="SelectionStates">
7: <VisualState x:Name="Selected">
8: <Storyboard>
9: <Storyboard.Children>
10: <Storyboard>
11: <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="ellipse" Storyboard.TargetProperty="(UIElement.Visibility)">
12: <DiscreteObjectKeyFrame KeyTime="00:00:00">
13: <DiscreteObjectKeyFrame.Value>
14: <Visibility>Collapsed</Visibility>
15: </DiscreteObjectKeyFrame.Value>
16: </DiscreteObjectKeyFrame>
17: <DiscreteObjectKeyFrame KeyTime="00:00:00.01">
18: <DiscreteObjectKeyFrame.Value>
19: <Visibility>Visible</Visibility>
20: </DiscreteObjectKeyFrame.Value>
21: </DiscreteObjectKeyFrame>
22: </ObjectAnimationUsingKeyFrames>
23: </Storyboard>
24: <Storyboard RepeatBehavior="ForEver">
25: <DoubleAnimation BeginTime="0" Storyboard.TargetName="ellipse" Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)" From="1" To="10" Duration="00:00:01" />
26: <DoubleAnimation BeginTime="0" Storyboard.TargetName="ellipse" Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)" From="1" To="10" Duration="00:00:01" />
27: <DoubleAnimation BeginTime="0" Storyboard.TargetName="ellipse" Storyboard.TargetProperty="(UIElement.Opacity)" From="1" To="0" Duration="00:00:01" />
28: </Storyboard>
29: </Storyboard.Children>
30: </Storyboard>
31: </VisualState>
32: <VisualState x:Name="Unselected" />
33: </VisualStateGroup>
34: </VisualStateManager.VisualStateGroups>
35: <Ellipse Height="20" Width="20" Canvas.Left="-10" Canvas.Top="-10" RenderTransformOrigin="0.5,0.5" x:Name="ellipse" IsHitTestVisible="False" Visibility="Collapsed">
36: <Ellipse.RenderTransform>
37: <ScaleTransform />
38: </Ellipse.RenderTransform>
39: <Ellipse.Fill>
40: <RadialGradientBrush>
41: <GradientStop Color="#00FF0000" />
42: <GradientStop Color="#FFFF0000" Offset="0.25" />
43: <GradientStop Color="#00FF0000" Offset="0.5" />
44: <GradientStop Color="#FFFF0000" Offset="0.75" />
45: <GradientStop Color="#00FF0000" Offset="1" />
46: </RadialGradientBrush>
47: </Ellipse.Fill>
48: </Ellipse>
49: <Image Height="60" Width="60" Canvas.Left="-30" Canvas.Top="-30" Source="Images/SuperMarket.png" x:Name="ellipse1" />
50: </Canvas>
51: </ControlTemplate>
52: </esriSymbols:MarkerSymbol.ControlTemplate>
53: </esriSymbols:MarkerSymbol>
好了,已经完成了我们的准备工作。下节中,我们来完成点击查询(Identity)的功能。
相关链接:
超市信息的shapefile下载:
https://blog.newnaw.com/wp-content/uploads/2011/03/supermarket_shp.zip
Map控件中添加图层:
http://help.arcgis.com/en/webapi/silverlight/help/0166/016600000019000000.htm
GraphicsLayer概述:
http://help.arcgis.com/en/webapi/silverlight/help/0166/01660000001q000000.htm
GraphicsLayer详述:
http://bbs.esrichina-bj.cn/ESRI/thread-44892-1-1.html
FeatureLayer概述:
http://help.arcgis.com/en/webapi/silverlight/help/0166/016600000015000000.htm
图层类型小结:
http://bbs.esrichina-bj.cn/ESRI/thread-45537-1-1.html
ArcGIS API for Windows Phone/Silverlight/WPF中自定义符号:
http://help.arcgis.com/en/webapi/silverlight/samples/SymbolGalleryWeb/start.htm
Silverlight中的StaticResource:
http://msdn.microsoft.com/en-us/library/cc189045(v=vs.95).aspx
您好,看了您的文字,受益颇多,但我自己写代码时发现一个问题,即有的FeatureLayer里一个Graphic都没有,而有的FeatureLayer里只有一部分Graphic或Graphic形状不正确,无论FeatureLayer的Url是MapServer的子图层还是FeatureServer的子图层。而我马上就要用到FeatureLayer,因此我急切地希望能尽早地得到您的指点。
你好,featurelayer与graphiclayer一样,显示内容的关键是graphic要有正确的图形和正确的符号。确保symbol和geometry,尤其是空间参考,正确,即可正常显示。
您好,我成功加载了featurelayer,但地图控件上显示的是我在ArcMap里定义的符号。并且在Arcgis runtime sdk for windowsphone3.0里的FeatureLayer的属性里我找不到FeatureSymbol属性,所以没法通过您文中的方法更改要素符号。请问有什么其他的方法更改符号不?