Category Archives: 从这里发布的

从blog.newnaw.com发布的

ArcGIS API for Windows Phone开发实例(5):对超市信息进行空间查询

  本文内容:ArcGIS API中Task的概念,QueryTask的使用,以及Draw对象。
  空间查询GIS中一个非常常用的功能:在地图上画出任意多边形,从自己感兴趣的事物中筛选出与所画多边形有指定空间关系(通常是相交)的要素来,进一步查看。在本次开发实例中,第二个功能就是空间查询。用手势在地图上画一个范围,筛选出落入该范围的超市店面,从而进一步查看它们的营业额统计信息。
  ArcGIS API中,给我们提供了许多Task类,来完成一些常见的GIS功能,比如属性/控件查询,几何对象的拓扑处理,特定工作流的地理任务等。它们都是已经封装好的Task类,使用起来都遵循3个步骤的原则:1、为某个Task设置所需的相应参数;2、通过Task对象向服务器发送处理请求;3、接受服务器端返回的结果。所有的计算和处理工作都是由ArcGIS Server发布的REST服务来完成,是典型的客户端请求,服务器端相应的流程。
  QueryTask是ArcGIS API提供的诸多Task之一,它接受Query类型的参数。该参数有几个常用的属性,比如Where属性和Geometry属性,通过对这两个属性的设置,我们就可以完成最常见的属性查询和空间查询功能。依然将空间查询这个功能封装成一个工具,在主界面中进行调用。

clip_image002

  这里为了清晰起见,我省去与空间查询功能无关的代码(所有程序代码会在教程完结后提供下载)。要使用QueryTask的功能,我们按照前面说三个步骤来做。首先设置好查询参数Query,然后通过QueryTask对象提交查询请求:

   1: void _draw_DrawComplete(object sender, DrawEventArgs e)

   2:         {

   3:             Polygon polygon = null;

   4:             if (_usingFreeHand) //geometry is freehand polyline

   5:             {

   6:                 Polyline polyline = e.Geometry as Polyline;

   7:                 ESRI.ArcGIS.Client.Geometry.PointCollection pc = polyline.Paths[0];

   8:                 pc.Add(pc[0]);

   9:                 polygon = new Polygon()

  10:                 {

  11:                     SpatialReference = map1.SpatialReference,

  12:                 };

  13:                 polygon.Rings.Add(pc);

  14:             }

  15:             else //geometry is polygon

  16:             {

  17:                 polygon = e.Geometry as Polygon;

  18:             }

  19:  

  20:             _GLayer.Graphics.Clear();

  21:             Graphic g = new Graphic()

  22:             {

  23:                 Geometry = polygon,

  24:                 Symbol = new SimpleFillSymbol()

  25:                 {

  26:                     Fill=new SolidColorBrush(Color.FromArgb(33,255,0,0)),

  27:                     BorderBrush=new SolidColorBrush(Colors.Red),

  28:                     BorderThickness=2

  29:                 }

  30:             };

  31:             _GLayer.Graphics.Add(g); //display the geometry created by Draw object

  32:  

  33:             QueryTask queryTask = new QueryTask(App.Current.Resources["BusinessLayer"] as string);

  34:             Query query = new Query();

  35:             //102100 to 4326

  36:             ESRI.ArcGIS.Client.Projection.WebMercator wm = new ESRI.ArcGIS.Client.Projection.WebMercator();

  37:             query.Geometry = wm.ToGeographic(polygon);

  38:             query.OutFields.AddRange(new string[] { "*" });//return all attributes fields

  39:             query.SpatialRelationship = SpatialRelationship.esriSpatialRelIntersects;

  40:             queryTask.ExecuteCompleted += new System.EventHandler<QueryEventArgs>(queryTask_ExecuteCompleted);

  41:             queryTask.Failed += (s, a) =>

  42:             {

  43:                 MessageBox.Show("查询失败" + a.Error.Message);

  44:             };

  45:             _busyIndicator.Visibility = Visibility.Visible;

  46:             queryTask.ExecuteAsync(query);     

  47:         }

  代码中,我们首先利用超市图层的服务地址,初始化了一个QueryTask对象。对于Query参数,这里设置了Geometry属性,作为空间查询的图形;对OutFields参数的设置表示在查询结果中返回所有属性字段;指定空间关系为与Geometry相交。然后通过ExecuteAsync方法将查询请求提交到服务器端。注意到在设置Query的Geometry属性之前,我们对Polygon对象做了空间参考的转换,将其从102100坐标系(WGS 1984 Web Mercator Auxiliary Sphere,这是地图控件的坐标系)转换到了4326坐标系(WGS 1984,这是超市图层的坐标系),如果Query中Geometry的坐标系不正确,查询结果往往会不可预料。
  发出请求后,我们就可以在设置好的queryTask_ExecuteCompleted方法中取得查询结果了。

   1: void queryTask_ExecuteCompleted(object sender, QueryEventArgs e)

   2:         {

   3:             _busyIndicator.Visibility = Visibility.Collapsed;

   4:             if (e.FeatureSet.Features.Count == 0) //typeof(e.FeatureSet.Features)==GraphicCollection

   5:             {

   6:                 MessageBox.Show("未选中任何店面");

   7:             }

   8:             else

   9:             {

  10:                 string str = "是否查看图表详情?";

  11:                 if (MessageBox.Show(str,

  12:                 "查询结果", MessageBoxButton.OKCancel) == MessageBoxResult.OK)

  13:                 {

  14:                     //add selected graphics to app level, so spatialquerychart.xaml could retrieve them

  15:                     App app = Application.Current as App;

  16:                     if (app.AppParameters.ContainsKey("QueryedGraphics"))

  17:                         app.AppParameters["QueryedGraphics"] = e.FeatureSet.Features;

  18:                     else

  19:                         app.AppParameters.Add("QueryedGraphics", e.FeatureSet.Features);

  20:  

  21:                     (app.AppParameters["MainPage"] as PhoneApplicationPage).NavigationService.Navigate(new Uri("/Tools/SpatialQueryChart.xaml", UriKind.Relative));

  22:                 }

  23:                 _GLayer.ClearGraphics();

  24:             }

  25:         }

  可以看到,查询结果(落入所选范围内的超市)以Graphic的形式存储在事件参数中。Graphic的Geometry就是超市的图形信息,而Attributes属性中是我们想要的所有营业信息。如果查询结果不为空,我们将其存入全局变量中,以便在另一个页面中用图表的形式来显示。这里我们使用VisiFire控件来显示图表,它是一套可用于WP上的Silverlight插件,此处不进行过多讨论,有兴趣同学可自己搜索。
  整个查询的过程在QueryTask的帮助下变得非常简单。细心的朋友可能会有疑问,我们这个空间查询的图形是如何得到的?在前面的代码中可以看到,发起查询请求的代码是写在_draw_DrawComplete这个事件中的。_draw是我们提前定义好的一个Draw对象:private Draw _draw;。
  为了方便与用户的交互,ArcGIS API中提供了Draw这个类,可以利用鼠标或手势来交互地画出Point,Polyline,Polygon,Freehand(Polyline)等几何对象,在2.2版本的API中,Draw还新增了arrow,triangle,circle,ellipses几个原生图形。

clip_image002

  使用Draw这个对象也比较简单,初始化,设定好要画的几何图形类型,然后将其IsEnabled属性设为True,就进入了交互状态,绘制完毕后,就会触发DrawComplete事件,在事件的参数中就可以得到画出的Geometry结果,得到结果之后,就可以利用Graphic将这个看不见摸不着的Geometry显示出来了,这样就达到了交互的目的。我们空间查询的几何对象就是利用Draw得到的。

clip_image004

clip_image006

参考资料:

ArcGIS API中各种Task介绍:
http://bbs.esrichina-bj.cn/ESRI/thread-45302-1-1.html

Draw对象的使用:
http://help.arcgis.com/en/arcgismobile/10.0/apis/WindowsPhone/help/011v/011v00000019000000.htm

QueryTask的使用:
http://help.arcgis.com/en/arcgismobile/10.0/apis/WindowsPhone/help/011v/011v00000016000000.htm

VisiFire:
http://www.visifire.com/

ArcGIS API for Windows Phone开发实例(4):点击查看超市信息

  本文内容:Silverlight的自定义UserControl,NavigationService(页面导航),WP的Application Bar,ArcGIS API的ElementLayer。
  上一节中,已经完成了程序的准备工作,利用FeatureLayer来显示超市位置,接下来的几篇文章中我们就来依次实现程序的四个功能点:

  • 点击查看某个超市的详细信息;
  • 按空间范围查看某几个店面的销售总额;
  • 按时间的方式动态查看每个店面的营业情况;
  • 对某个店面的近期营业情况做出具体分析。

  第一个功能在GIS中叫做Identify。这个功能的作用是,当使用者激活该功能后,点击地图上的某个超市图标,会弹出一个类似气泡的小窗口(InfoWindow)显示超市名称,点击这个气泡后,程序可导航到另一个页面来显示该超市的详细信息。
  由于很多功能都是利用单击地图的方式来实现,为了不让这些功能混淆,我将程序中的四个功能分别做成不同的工具(封装成不同的类),点击某个工具后就激活它,此时地图或其中的控件就响应该工具的功能。
  我们在工程中新建一个文件夹Tools,放置与功能点有关的类;并在其中新建一个Identify.cs的文件,用来实现我们的第一个功能点。

clip_image002

   1: public class Identify

   2:     {

   3:         private bool _isActivated;

   4:         private ElementLayer _elementLayer; //InfoWindow layer 

   5:         public Map _map1 { get; set; }

   6:         public GraphicsLayer GLayer { get; set; } //supermarket layer

   7:         public bool IsActivated

   8:         {

   9:             get { return _isActivated; }

  10:             set

  11:             {

  12:                 if (_isActivated != value)

  13:                 {

  14:                     _isActivated = value;

  15:                     if (value)

  16:                     {

  17:                         if(_elementLayer ==null)

  18:                             _ elementLayer = new ElementLayer();

  19:                         if (!_map1.Layers.Contains(_elementLayer))

  20:                             _map1.Layers.Add(_elementLayer);

  21:                         GLayer.MouseLeftButtonDown += GLayer_MouseLeftButtonDown;

  22:                     }

  23:                     else

  24:                     {

  25:                         if (_map1.Layers.Contains(_elementLayer))

  26:                             _map1.Layers.Remove(_elementLayer);

  27:                         GLayer.MouseLeftButtonDown -= GLayer_MouseLeftButtonDown;

  28:                         if (GLayer.SelectedGraphics.Count() > 0)

  29:                             GLayer.SelectedGraphics.ToList()[0].UnSelect();

  30:                         _ elementLayer.Children.Clear();

  31:                     }

  32:                 }

  33:             }

  34:         }

  35:         

  36:         public Identify(Map map,GraphicsLayer glayer)

  37:         {

  38:             _map1 = map;

  39:             GLayer = glayer;

  40:         }

  41:     }

在这个类(Identify工具)的构造函数中,有两个参数:一个Map控件和一个GraphicsLayer,分别是我们程序中的Map控件和超市图层FeatureLayer(继承自GraphicsLayer),因此我们可以在Identify工具中控制它们的行为。
  IsActived属性控制着这个工具的状态,如果IsActived=ture,则该工具处于激活状态,此时地图和超市图层响应Identify工具规定的行为;如果IsActived=false,则代表程序不使用该工具,做一些清理工作。其他工具也是如此,可以用代码来控制某一时刻只能有一个工具处于激活状态。
  另外我们还可以看到,Identify这个类中还有一个ElementLayer类型的_Elayer属性。ElementLayer是ArcGIS API for Windows Phone/Silverlight/WPF中的一种图层类型,主要用来承载Silverlight中的原生对象(UIElement),比较关键的一点是,ElementLayer中的元素会随着地图范围的变化而变化(缩放/平移),而不用自己去处理这些UIElement的地理坐标。所以在这里我们就用ElementLayer来放置我们的气泡(InfoWindow)。
  来看一下Identify的主要功能:

   1: void GLayer_MouseLeftButtonDown(object sender, GraphicMouseButtonEventArgs e)

   2:         {

   3:             if (GLayer.SelectedGraphics.Count() > 0)

   4:                 GLayer.SelectedGraphics.ToList()[0].UnSelect();

   5:  

   6:             Graphic g = e.Graphic;

   7:             _ELayer.Children.Clear();//remove other infowindow

   8:             InfoWindow infoWindow = new InfoWindow(_ELayer, e.Graphic);

   9:             ESRI.ArcGIS.Client.ElementLayer.SetEnvelope(infoWindow, new Envelope((e.Graphic.Geometry as MapPoint), (e.Graphic.Geometry as MapPoint)));

  10:             _ELayer.Children.Add(infoWindow);

  11:  

  12:             e.Graphic.Select();

  13:         }

  GraphicsLayer(超市图层)的MouseButtonDown事件可以保证,只有当点击到某个Graphic(超市)后,才会触发此事件,而点击空白地方是不会触发此事件的。我们在这里并需要做任何查询操作,就可以通过被点击Graphic的Attributes属性获得该超市的所有信息,因为所有超市的属性信息(还记得OutFields属性的“*”吗)在FeatureLayer初始化的时候,已经被传送到了客户端(手机上)。点击某个超市后,屏幕上会出现一个气泡(InfoWindow类)显示超市店名。

clip_image002[5]

  这个类是我们自定义的一个UserControl,可以很方便的给其中加入额外的功能,比如点击了这个InfoWindow后,将程序导航到超市详细信息的页面。关于这个InfoWindow类详细代码以及在线例子,可以在这里查看。此外2.1以后版本的API中也提供了InfoWindow的ToolKit,有兴趣的同学可以在这里查看
  Windows Phone程序中,由于屏幕尺寸原因,如果需要另外显示比较多的内容,则需要将程序导航到一个新的页面中,比如这里我们需要显示超市的详细信息。

clip_image004

  所以在InfoWindow本身的单击事件中,用下面的代码将程序导航到显示超市详细信息的页面(Attributes.xaml)。

   1: private void Canvas_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)

   2:         {

   3:             //add clicked graphic to app level, so attributes.xaml could access it

   4:             App app = Application.Current as App;

   5:             if (app.AppParameters.ContainsKey("IdentifyGraphic"))

   6:                 app.AppParameters["IdentifyGraphic"] = Graphic;

   7:             else

   8:                 app.AppParameters.Add("IdentifyGraphic", Graphic);

   9:             (app.AppParameters["MainPage"] as PhoneApplicationPage).NavigationService.Navigate(new Uri("/Tools/Attributes.xaml", UriKind.Relative));

  10:         }

  其中重要的类是NavigationService,每个Windows Phone的页面(PhoneApplicationPage)都有这样一个属性。在多页面的Silverlight程序中也使用此类来导航。虽然Navigate方法可以在页面之间传递参数(类似asp.net),但仅限于string类型,因此我们的超市属性信息集合不好处理。我在App.xaml.cs文件里的Application类中,定义一个全局的Dictionary,用于存储我们需要用到的全局变量。

   1: //used to store variables which need to pass from one page to another

   2:         public Dictionary<string, object> AppParameters;

  先将被点击的Graphic存入程序的Silverlight的全局变量AppParameters中,然后在Attributes.xaml页面就能取到。Attributes.xaml中用ListBox控件来显示超市信息,由于Windows Phone基于Silverlight 3,而Graphic的属性信息Attributes是Dictionary集合,dictionary binding在Silverlight 4中才支持,所以这里我们依然需要使用到DictionaryConverter来在绑定过程中进行转换。Attributes.xaml页面:

   1: <!--ContentPanel - place additional content here-->

   2:         <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">

   3:             <ListBox x:Name="listbox" Margin="0,0,-12,0" ItemsSource="{Binding}">

   4:                 <ListBox.ItemTemplate>

   5:                     <DataTemplate>

   6:                         <StackPanel Margin="0,0,0,17" Width="432">

   7:                             <Canvas>

   8:                                 <Rectangle Fill="#FF83919D" Canvas.Left="0" Canvas.Top="0" Height="31" Width="800"/>

   9:                                 <TextBlock Text="店名"

  10:                         TextWrapping="Wrap" Margin="12,-4,4,5" FontSize="26" Foreground="White"/>

  11:                             </Canvas>

  12:                             <TextBlock Text="{Binding Path=Attributes, Converter={StaticResource MyDictionaryConverter}, ConverterParameter=Name}" 

  13:                             TextWrapping="Wrap" FontSize="30" Margin="12,28,12,3" Foreground="#FF188DC6"/>

  14:                             <Canvas>

  15:                                 <Rectangle Fill="#FF83919D" Canvas.Left="0" Canvas.Top="0" Height="31" Width="800"/>

  16:                                 <TextBlock Text="地址"

  17:                         TextWrapping="Wrap" Margin="12,-4,4,5" FontSize="26" Foreground="White"/>

  18:                             </Canvas>

  19:                             <TextBlock Text="{Binding Path=Attributes, Converter={StaticResource MyDictionaryConverter}, ConverterParameter=Address}" 

  20:                             TextWrapping="Wrap" FontSize="30" Margin="12,28,12,3" Foreground="#FF188DC6"/>

  21:                             。。。。。。。。。。。。

  22:                         </StackPanel>

  23:                     </DataTemplate>

  24:                 </ListBox.ItemTemplate>

  25:             </ListBox>

  26:         </Grid>

  Attributes.xaml.cs文件:

   1: public partial class Attributes : PhoneApplicationPage

   2:     {

   3:         private Graphic _graphic;

   4:         public Attributes()

   5:         {

   6:             InitializeComponent();

   7:  

   8:             _graphic = (Application.Current as App).AppParameters["IdentifyGraphic"] as Graphic;

   9:             GraphicCollection gc = new GraphicCollection();

  10:             gc.Add(_graphic);

  11:             listbox.ItemsSource = gc;

  12:         }

  13:     }

  完成了整个Identify功能后,在MainPage.xaml页面中,我们在Application Bar中添加四个按钮,点击某个按钮后,就激活相应的工具。比如在点击了Identify功能按钮后,我们需要将Identify工具的IsActived属性设为true,将其他工具的IsActived属性设为false。最后别忘了,在超市图层FeatureLayer初始化时(Update事件),实例化我们的四个工具:

   1: public partial class MainPage : PhoneApplicationPage

   2:     {

   3:         private Identify _OpIdentify;

   4:         private SpatialQuery _OpSpatialQuery;

   5:         private TimeQuery _OpTimeQuery;

   6:         private Analysis _OpAnalysis;

   7:         private FeatureLayer _FLayer;

   8:  

   9:         // Constructor

  10:         public MainPage()

  11:         {

  12:             InitializeComponent();

  13:             _FLayer = map1.Layers["BusinessLayer"] as FeatureLayer;

  14:             _FLayer.UpdateCompleted += (s, a) =>

  15:             {

  16:                 //Add MainPage to app level, so other pages can navigates from it.

  17:                 App app = Application.Current as App;

  18:                 if (!app.AppParameters.ContainsKey("MainPage"))

  19:                     app.AppParameters.Add("MainPage", this);             

  20:                 _OpIdentify = new Identify(map1, _FLayer);

  21:                 _OpSpatialQuery = new SpatialQuery(map1, BusyIndicator);

  22:                 _OpTimeQuery = new TimeQuery(map1);

  23:                 _OpAnalysis = new Analysis(map1,this,BusyIndicator);

  24:             };

  25:         }

  26:     }

  下一节中,我们来实现按空间范围查看某几个店面的销售总额的功能,也就是SpatialQuery这个类。

参考资料:

Windows Phone中的Application Bar和Application Menu:
http://msdn.microsoft.com/en-us/library/ff431801(v=VS.92).aspx

Windows Phone中的页面和导航框架:
http://msdn.microsoft.com/en-us/library/ff402536(v=vs.92).aspx

Silverlight中自定义UserControl:
http://www.cnblogs.com/Terrylee/archive/2008/03/08/Silverlight2-step-by-step-part10-using-user-controls.html

ArcGIS API for Windows Phone/Silverlight/WPF中的ElmentLayer:
http://help.arcgis.com/en/webapi/silverlight/samples/start.htm#ElementLayer

ArcGIS API for Windows Phone开发实例(3):在地图上显示超市数据

  本文内容: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。这个过程不属于本文要讨论的内容,不熟悉的同学可自己查阅相关资料。超市图层的属性表如下,前面是每个店面的基本信息,后面是该月每天的营业额信息:

image

  超市的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控件的最底端,如图:

clip_image002[9]

  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>

  运行一下

image
 
  可以看到,超市已经显示在地图上面了。但超市的符号依然是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>

clip_image002[11]

  好了,已经完成了我们的准备工作。下节中,我们来完成点击查询(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

ArcGIS API for Windows Phone开发实例(2):HelloMap

  本文内容:WP开发环境的搭建和第一个程序HelloMap。所有参考资料都会给出相应链接,供仔细的朋友进一步学习,后同。

一、开发环境搭建

  1、安装微软的Windows Phone Developer Tools。微软的开发离不开Visual Studio,Silverlight开发又需要Silverlight Tools for Visual Studio,WP的开发需要Windows Phone Developer Tools…看起来有点复杂,其实很简单,只需到APP HUB网站,按照1、2、3的说明依次安装即可。如图:

clip_image002

  其中最主要的是1中提到的Windows Phone Developer Tools,它会下载一个3.2M大小的vm_web.exe安装程序,这其实是一个安装工具,不管你的机器是否安装了VS 2010(不支持以前的版本),是否安装了Silverlight Tools,它都会检测你机器开发WP程序所需的所有工具,并提示你进行安装(比如没有VS的话会为你安装VS 2010 Express,已有的就不再重复提示了),有点类似1 click install,非常方便。如果你的机器上什么都没有,那么它会依次提示你安装以下几个工具:

clip_image004

  另外APP HUB网页上第二步中提到的Windows Phone Developer Tools January 2011 Update修复了最初版本中的bug,提供了一个新的模拟器,以及一些新的特性,比如拷贝和粘贴。第三步中提到的Windows Phone Developer Tools Fix修正了不能给真机上部署超过64M大小的XAP文件的bug。所以,2、3属于选装,但强烈推荐安装。
  安装完成之后,打开VS 2010,新建工程中应该能够看到以下画面:

clip_image006

  至此,我们已经可以用Silverlight开发WP的应用程序了。
  另外,与Silverlight Toolkit类似,微软还提供了Silverlight for Windows Phone Toolkit,地址都在这里。它们都是封装好的,开源的一些控件或效果,用来补充自带控件的不足,为你的程序增加效果。
  2、安装Esri的ArcGIS API for Windows Phone。ArcGIS API for Windows Phone与ArcGIS for Silverlight/WPF一样,是Esri免费提供给我们的开发包,里面包含了几个dll文件(包含各种类,函数)供我们引用。目前最新版本是2.2 beta,可利用自己的Esri Global Account(可免费申请)登陆Beta Community后进行下载。如果你不想参与beta community,也可以在这里按照提示下载2.1版本的API。2.2 beta版本的API提供了exe安装程序(2.1版本没有),安装好后,你可以在安装目录中找到以下内容:

clip_image008

  • ESRI.ArcGIS.Client.dll。这是API中的核心类库,包括最常用的Map控件,各种图层类,Graphics,Geometry,Symbols等,同时还包括了各种Task:Identity,Find,Query,Geoprocessing等;
  • ESRI.ArcGIS.Client.Bing.dll。如果你需要在程序中调用Bing Maps的底图或使用它的Geocoding或Routing服务,则需要这个dll;
  • ESRI.ArcGIS.Client.Toolkit.dll。类似Silverlight Toolkit,是Esri提供的已经封装好的,开源的,一些常用控件,比如缩略图,书签,导航条,InfoWindow等,可以在这里下载它们的源码
  • ESRI.ArcGIS.Client.Toolkit.DataSources.dll。提供对一些通用数据源的加载支持,比如OpenStreetMap,WMS服务,KML等,可以在这里下载它们的源码
  • ESRI.ArcGIS.Client.WebMap.dll。可用于加载ArcGIS Online的在线地图。

  好了,下面我们就可以开始我们的第一个应用程序HelloMap了。

二、 HelloMap

  打开VS 2010,New Project,左侧选择Silverlight for Windows Phone,右侧Windows Phone Application,然后OK:

clip_image010

  可以看到新建好的工程中包含几个文件,我们对其中几个xaml类型文件做一下解释。Silverlight开发中,文件主要分为两种类型,以.xaml结尾的文件和以.xmal.cs(或.xaml.vb)结尾的文件,前者是一种扩展的xml语言,负责页面的布局、样式,后者是普通的代码文件,主要负责程序的逻辑功能。界面与功能很清楚地分离开来。App.xaml(App.xaml.cs)是程序的入口,与应用程序相关的全局事件,比如进入或退出应用程序都在这里;MainPage.xaml(MainPage.xaml.cs)是自动创建的主页面,程序默认会启动这个页面。注:你也可以在WMAppManifest.xml文件中来显示指定程序的第一个启动页面。
  因为我们要使用API中的Map控件,所以先添加对ESRI.ArcGIS.Client.dll的引用(如果是2.1版本,需要手动Browse到这个dll):

clip_image012

  然后在MainPage.xaml中为这个dll引入一个namespace(类似代码文件中的using):

clip_image014

  接下来添加我们用以显示地图的Map控件。在MainPage.xaml中找到名为ContentPanel的Grid部分,在其中添加我们的Map控件,并在加入一个底图图层:

   1: <!--ContentPanel - place additional content here-->

   2:         <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">

   3:             <esri:Map x:Name="MyMap">

   4:                 <esri:ArcGISTiledMapServiceLayer ID="MyLayer" 

   5:                     Url="http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer" />

   6:             </esri:Map>

   7:         </Grid>

  按F5,编译运行(注意将Targets选择为Windows Phone Emulator而不是Windows Phone Device),会启动Windows Phone模拟器,就完成了我们的HelloMap程序。

clip_image016

  解释一下。Grid是Silverlight里最常用的布局控件之一(另外还有StackPanel和Canvas),类似于Html里的Table,可自行搜索学习或参考这里;x:Name相当于该元素的一个id,便于在.cs的代码页面中直接引用。
  Map控件是ArcGIS API for Windows Phone中最基本的控件,所有能够看见的与地图有关的元素都将呈现在这个控件以内。但它本身是空的,所以我们需要给其中添加一个图层,用以显示上面的地图。我们这里使用的图层类型是ArcGISTiledMapServiceLayer,它专门并且只能用于加载ArcGIS Server发布的经过切片的缓存地图服务,与之相对应的还有ArcGISDynamicMapServiceLayer,专门并且只能用于加载ArcGIS Server发布的动态地图服务,以及ArcGISImageServiceLayer,用于加载ArcGIS Server发布的影像服务。这里的Url是一个地图服务的REST方式的节点,可通过ArcGIS Server的Service Directory查看。比如我们可以查看通过http://services.arcgisonline.com/arcgis/rest/services 这个地址查看ArcGIS Online上发布的所有服务。在这里你并不需要掌握有关ArcGIS Server的任何知识,只需要知道所有的资源,包括地图,查询等功能都是服务器端ArcGIS Server通过服务形式暴露给你的,而我们只需通过一个Url去引用它即可。当然如果你对ArcGIS Server感兴趣的话,可以在这里找到资料。
  好了,这就是我们HelloMap的所有内容。最后给出几个相关链接,也是我们学习过程中最常用到的资料,如能掌握,则可事半功倍。

关于Map控件和图层的详细解释:http://help.arcgis.com/en/arcgismobile/10.0/apis/WindowsPhone/help/011v/011v00000005000000.htm

ArcGIS API for Windows Phone的在线例子(可操作,有源码):http://help.arcgis.com/en/arcgismobile/10.0/apis/WindowsPhone/samples/start.htm

关于WP7的知识,推荐Windows Phone 7 in 7 Minutes!系列视频教程,全面、快速、易懂

关于ArcGIS Server的知识:http://help.arcgis.com/en/arcgisserver/10.0/help/arcgis_server_dotnet_help/index.html

ArcGIS API for Windows Phone开发实例(1):准备工作

  本文有三部分内容。注:以后的文章中以WP作为Windows Phone的简写。

一、Windows Phone开发需要哪些知识?

  先来看一下WP的整体结构:

clip_image002

  最底下是通用的基础类库,可以当做是.NET Framework中保留了核心功能的简化版CLR;最上层是WP特有的类库,提供给开发者与手机相关的功能,比如说屏幕控制,摄像头控制,获取位置等等。
  中间这层是WP为我们提供的两套开发框架:Silverlight或XNA。也就是说,你可以利用Silverlight技术或者XNA技术来开发运行在WP上的应用程序。大致地,在WP上,Silverlight适合编写大多数应用程序,XNA适合编写游戏程序。XNA是微软提供的一套游戏开发环境,它有多强大,看看XBOX有多成功就知道了,感兴趣的同学可以深入研究。Silverlight是微软抢占RIA市场的有力武器之一,也是以后微软.NET Framework中主打开发技术之一——WPF——的子集。作为.NET开发人员,如果还不熟悉的话,有必要赶紧熟悉一下。关于它的介绍很多,可以参考我之前写的这篇,或者自己搜索。
  要强调的一点是,你在别处写的Silverlight或XNA程序基本不需要或只需要进行少量的更改(比如屏幕尺寸调整或使用WP的硬件功能),便可顺利运行在WP上,这是微软统一的开发平台给我们带来的好处。
  这次,我们只关心Silverlight,它就是开发WP程序所需的知识。

二、ArcGIS API for Silverlight/WPF和ArcGIS API for Windows Phone的异同?

  在比较Esri的这几个客户端API之前,我们需要看一看Windows Phone上使用的Silverlight技术和普通的Silverlight技术有什么区别。目前是WP的第一个版本,也就是Windows Phone 7,它所使用的Silverlight开发技术是基于3版本的,在WP开发中你基本可以使用Silverlight 3的所有特性,还包括WP特有的触控功能。具体可参考这两篇文章:Features Supported in Silverlight for Windows PhoneDifferences Between Silverlight and Silverlight for Windows Phone。需要强调的一点是,Silverlight 4的新特性在WP上基本无法使用,对此我们只能表示遗憾。但可以期待在以后的WP版本中,Silverlight版本能够与其他平台统一起来。
  那么Esri的这三个API(最新的2.2beta版本中已将Silverlight和WPF两个API分开)就比较好理解了。ArcGIS API for Silverlight,ArcGIS API for WPF,ArcGIS API for Windows Phone三者的功能,架构,包括源代码完全一致,只是编译的目标平台不同。对于Esri的这三个API,你只需熟悉其中之一,就可以在其他两个平台上进行开发。
  所以,如果你没有学过ArcGIS API for Silverlight的话也没有关系,会了Windows Phone API,你也就学会了Silverlight API。

三、我们要完成的工作

  在上一篇文章中,我们已经了解到,最终我们需要完成这么一个WP上的应用程序:连锁超市的老板出差在外,在机场候机的过程中想查看一下自己的几家店面最近的营业情况。传统的统计报表只能通过电子邮件发送给老板,他需要不停的查看自己的邮箱;而里面的内容既不直观也不易懂。将报表数据发布成地图服务,这样即可在任何时间任何地点访问业务数据,也可通过地图的方式充分挖掘数据的潜在价值。老板通过windows phone7上的地图应用,对自己店面近来营业情况一目了然,利用应用所提供的分析功能,即使在千里之外也能随时对自己的生意轻松经营。
  好了,要了解的预备知识已经梳理完毕。有人可能说,都看了这么多了,还没进入动手阶段?我是希望大家每时每刻都知道我们在做什么,为什么要这么做,知其然也知其所以然。就跟听别人的PPT一样,对于我们不熟悉的内容,如果前面两页他交代不清楚,可能整个PPT就是在浪费我们的时间。凡事皆如此。

ArcGIS API for Windows Phone开发实例(0):为什么选择Windows Phone?

为什么要了解Mobile GIS?

  GIS技术固然有自己独特的理论知识,但GIS的实际应用离不开IT技术,GIS应用的发展离不开主流IT技术的发展。上面这句话我们可以看做一条公理,公理是不需要证明的。GIS技术的应用,从C/S到B/S,从SOAP到REST,从SOA到云,都印证了这条公理。
  从台式机到笔记本,从上网本到平板电脑和遍地开花的智能手机,移动不仅是IT技术的发展趋势之一,也是所有硬件的发展趋势。
  综上所述,作为GISser的你,没有理由不了解Mobile GIS技术。

ArcGIS移动产品线

  为什么要学习ArcGIS API for Windows Phone?从两个角度来回答:ArcGIS和Windows Phone。ArcGIS目前有5种移动产品,所有产品的介绍,帮助,下载详见这里

  • ArcPad。这是一个开箱即用的软件产品,基于Windows Mobile平台,最新版本是ArcPad 10(支持Windows Mobile 6.5)。特点是数据采集精度高(可到分米级),支持并推荐采用完全离线作业方式,包含丰富的GIS功能,比如图形(有捕捉功能)/属性/符号编辑,图层管理等,界面类似ArcMap,适合GIS专业人员使用,可通过界面或脚本语言进行定制。由于推出早(历经5.X,6.X,7.0,7.1,8.0.10几个版本),功能实用而丰富,收到广大用户青睐,目前全球用户超过100,000。
  • ArcGIS Mobile。是目前ArcGIS应用最广的移动产品之一,基于Windows Mobile平台,最新版本是ArcGIS Mobile 10.0(支持Windows Mobile 6.5)。特点是拥有自己的离线缓存格式,可完全离线使用,也可与ArcGIS Server随时进行各种粒度的缓存同步;基于任务模式,由工作流驱动,非GIS人员可以很快上手;可进行离线数据编辑,属性/空间查询,外业人员协作等任务;具有丰富的定制功能,并提供功能全面的SDK可进行二次开发。软件历经9.2,9.3,9.3.1,10.0几个版本,在国内拥有广大的用户群体。
  • ArcGIS for iOS。包括一个开箱即用的应用程序(ArcGIS for iOS Application,可在App Store中免费下载)和提供二次开发功能的ArcGIS API for iOS。基于苹果公司的iOS系统,可在iPhone,iPad,iPod Touch产品上运行。最初于2010年4月发布,目前应用程序和API版本是1.8。
  • ArcGIS for Windows Phone。包括一个开箱即用的应用程序(ArcGIS for Windows Phone Application,可在MarketPlace中免费下载)和提供二次开发功能的ArcGIS API for Windows Phone。基于微软公司的Windows Phone系统,可在基于该系统的手机上运行。最初于2010年9月发布,目前应用程序和API版本是2.2 beta。
  • ArcGIS for Android。基于Google公司的Android系统。目前ArcGIS API for Android处于public beta阶段,可在ArcGIS Beta Community中免费申请试用。正式版推出后,应该也会有开箱即用的应用程序,照惯例可通过Android Market免费下载。最初与2010年10月内测,今年2月底开始公测。

  以上三个产品(ArcGIS for iOS,ArcGIS for Windows Phone,ArcGIS for Android)是ArcGIS新一代的移动产品,就目前版本而言,大部分功能都是基于ArcGIS Server所发布的地图服务来使用(需要网络环境支持),包括地图操作,GraphicsLayer/FeatureLayer支持,各种Task(Identity/Query/Find/GeoProcessing等)的使用等。可以看出,这三种移动产品与ArcGIS客户端API(ArcGIS API for Javascript/Flex/Silverlight)所提供的功能基本一致,因此它们的概念和开发方式与三种客户端API无异。大家可能比较关心这三种API的离线使用方式,目前来说,理论上可以实现离线使用,但需要自己进行开发定制,可参考iOS中自定义图层的例子。以后的版本中肯定会加入离线模式,但目前无法给出具体的时间表。

为什么选择Windows Phone?

  现在最流行的手机操作系统有三种iOS,Android和Windows Phone。关于这三种操作系统究竟谁好谁坏,仁者见仁,每个人都有自己的答案。如果你是苹果的忠实粉丝,那么你可能对Android或Windows Phone系统不屑一顾,没关系,Android和Windows Phone用户也是这么想的。简单介绍一下。
  iOS。苹果公司的操作系统,用于其所有移动设备之上(iPhone/iPad/iPod Touch)。操作体验极好,界面华丽(容易吸引mm和领导),应用程序丰富;软硬件环境统一,用户群体相对固定,忠实度高;开发使用Objective C语言,难度相对较大。
  Android。Google公司的手机操作系统。07年底推出,占有率迅速上升,目前是市场占有率最高的智能手机系统。系统本身基于Linux,开源(软件版本多,定制版本多);集成google各种产品,包括gmail,gtalk,latitude等;应用软件丰富,用户群体广泛,以google的忠实用户为代表;开发基于Java语言。
  Windows Phone。微软公司2010年10月推出的新一代移动操作系统,用以取代即将被淘汰的Windows Mobile。不同于封闭的iOS和稍显混乱的Android,它的硬件环境统一,操作体验好;MarketPlace在不到半年的时间里,应用程序已达10,000个(我写文章这会是9643个);目前的生产厂商有HTC,Dell,三星,LG,还有即将加入的Nokia。
  你可能有很多理由不选择微软,但不管你喜欢不喜欢,它就在那里,不离不弃。这里给出选择Windows Phone的几个理由,供参考。
  1、微软的云+端战略。Windows Azure是微软自己的云平台,至于它的优劣,可以自己搜索。但有一点是肯定的,这是微软不惜重金打造的战略平台,在未来数年内会主导微软其他产品的发展方向,而微软也会不遗余力的推广它。端是指客户端,包括电脑,电视和移动端的手机,也就是Windows Phone了,所以其推广和宣传力度可知。
  2、Windows Phone上有两种开发架构,Silverlight和XNA。Silverlight和WPF是微软下一代的开发技术,而XNA是微软XBOX平台上的游戏开发技术。也就是说,不论是Silverlight的程序还是XNA的程序,基本上拿来就可以在Windows Phone上运行,效果不打折扣,这得益于微软统一的平台策略。给我们带来的直接好处就是,对于熟悉Silverlight或WPF的同学来说,Windows Phone的开发门槛几乎为零,而这两者所能够实现的功能,大家也是有目共睹,毋庸置疑。
  3、Windows Phone的娱乐性。XNA开发出的游戏得到了全球资深游戏玩家的一直认可,因为主流游戏平台就是PC+XBOX+PlayStation。如果你看过去年微软TechEd上Windows Phone的游戏演示(点这里),那你一定不会再留恋iOS上的极品飞车了。

讲座内容

  本系列文章内容以去年微软TechEd上的演示demo为例,从零开始,教你一步步完成这个Windows Phone应用程序实例。如果你学习过ArcGIS API for Silverlight,那么很好,你会在这里学到有关Windows Phone的开发知识;如果没学过,也没关系,本系列也会再次讲解API中所有的相关概念和内容。
  每篇文章内只提供相关代码和说明,希望在学习的过程中大家多思考为什么,而不是简单追求拷贝粘贴看效果。好了,该说的也都说了,如果你选择继续信任并使用Windows Phone,请继续关注;如果你对ArcGIS API for iOS感兴趣,请看barry.z的系列教程,如果你对ArcGIS API for Android感兴趣,请看牛魔王的系列教程

google maps中的中国式街景

  大家都知道google maps有个街景服务(street view),自07年推出起,目前已经覆盖了北美洲,欧洲,东亚大部分国家和地区的城市。这样即使我们足不出户,也可以浏览异国他乡的景色,比如看看英国的“伦敦眼”:


View Larger Map
  但由于某些原因,虽然google的街景已经完全覆盖了我国台湾,香港和澳门地区,但大陆地区的街景数据采集仍是遥遥遥遥遥遥无期。
  今天偶然发现,当你拖拽街景的小黄人到地图上的时候,除了能够浏览街景的主要街道以外,还有许多蓝色的热点地区可供浏览:
image
  而这些蓝色的热点区域是网友们上传到panoramio网站(以前被google收购)的照片。于是通过这些离散的照片,我们也能略微领略一下当地的风景了。
  赶紧看看你的家乡吧~
  ps:该功能必须使用英文版地图:http://maps.google.com才能浏览,中文版http://ditu.google.cn不提供;
  pps:欢迎围观我在panoramio上的照片~

我想和自己谈谈

  最近博客上连续都是所谓的技术文章,这样不好。原因有以下几点。
  一是因为容易被人误会我是一个纯技术爱好者,这个还不是事实。事实是这是我目前谋生的手段,既然看过了,好记性不如烂笔头,就把它们记下来,另外也好让需要这些东西的同学少些阅读长篇文字的痛苦;我也很羡慕那些真正的技术爱好者,因为他们可以利用自己的兴趣在某一方面推动人类历史发展的车轮,使人们的生活变得更加美好和有趣,如果有一天真能升华成这样的人,我也很荣幸。二是避免让有的同学拿“你才是做技术的,你全家都是做技术的”之类的语句来攻击我,起因是我俩曾在五道口地铁处看到过一个地摊,地摊摊主神似犀利哥,而摊上摆满了技术书籍,诸如《21天精通asp.net》,《php,java入门宝典》之类,5块一本,不还价。其实这都是玩笑话,是咱自己技不如人,但人家西班牙国家队成员还是很光荣的。三是主要原因,因为这些文章有内容,但没思想。思想无所谓好坏,只要是自己的就好,在生活中失去了自己的思想,是一件很可怕的事情。
  虽然我的肉身早已和大家一起进入了2011,但总觉得自己的2010还没有结束。结束的标志不是跨年倒数,也不是一篇年终总结,而是要把自己的思绪理一理,塞进时间的罐头中,然后盖好盖子,轻轻埋在心里。不论是这个动作的过程还是结果,对自己都有帮助。这就开始,结束我的2010。
  今年(应该是去年)最大的变化,就是开始工作了。结束自己长达十几年的学生生涯,突然过上了一种新的生活,肯定很不适应。和某些过程一样,在生理上和心理上都会产生阵痛。身体上的不适应表现在以前在学校想睡几点就睡几点,想什么时候玩就什么时候玩,想跟谁表白就跟谁表白,想吃什么就能吃到什么,而现在那些都变成了无比美好的回忆;六七月份同学们qq空间里那么多篇的感慨证明了我们思想上的不适应,严格意义上来说,我这篇也算,只是反应有点迟钝。就和我们小时候总希望变成大人一样,上学的时候总想着工作,可回过头来发现失去的东西才是最美好的。好在现在大家都已经适应了新的生活,也希望所有亲爱的同学们,不管是高中的还是大学的,和我一样,觉得虽然现在工作比原来在宿舍睡觉辛苦,但总体来说,感觉也还不错。很高兴告别那些所谓的科研项目,迎来现在平凡而有意义的工作,很高兴告别所谓的教授专家,迎来许多活泼可爱的同事们;离开空间狭小,硬件条件落后,软件环境也不优秀的地方很高兴,但离开母校,结束学生生涯,离开同学们还是伤感;离开一个生活了许多年的地方,新鲜和兴奋,但远离自己的亲人和家乡,还是伤感……
  前一阵看到一个词叫gap year,是指用一段较长的时间(通常是一年)去旅行或是从事一些非政府组织的志愿者工作。最常见的gap year包括高中毕业与升大学之间,大学毕业与工作之间,或者工作一段时间之后。想到别人的gap year,大家应该都充满了各种羡慕嫉妒恨,这点不难解释,就和所有人都喜欢下雪,所有人都喜欢旅游一样,the core of man’s spirit comes from new experiences。按照上面的说法,我似乎刚刚错过了一个gap year的机会,但也还不错,夏天的时候我有一个gap half month可以回忆。比起三年前一个人从西安到成都,这次和涛哥从西安骑车去北京的目的要简单和纯粹的多,不是驴友,不是户外,只是简单的自我锻炼和长长见识。能在这样一个低温少雨的冬季城市里,回想起当时汗流浃背,一天10瓶水的日子,夏天金灿灿的茫茫麦田和树荫下潺潺的清凉流水,疾驰时耳边的风声和困倦时田地里抱膝而憩,就像看着从桶里慢慢倒出酸奶一样,是一种享受。如果还有机会,我会毫不犹豫地选择再来一次。有人说这是一种疯狂,其实我觉得这还差得远。我更羡慕和向往在第10天遇到的三个学生,花了2个月时间从北京骑到了能目及珠峰的地方,南京的小胡花了十多天搭免费车25次回乌鲁木齐,Man vs Wild里Bear Grylls穿峡谷过沙漠的经历。不敢保证gap year一定不能实现,但心向往之,至少可以从gap day过起。
  关于济南。以前去过2次济南,每次停留的时间都很短,所看到的都是不起眼甚至在大城市人眼里看来有些落魄的外表,所想到的又是它省会的地位,自然和大多数外地人一样,认为这是一个没有吸引力的城市。但十月份的出差改变了我的看法,如果现在让我说,我挺喜欢她。和大部分陌生的山东人接触,让你不自觉的感受到他们的实在和直爽,不管是作为间接甲方的开发商还是早上卖早点的大娘。有一次吃饺子,饭馆人太多,只好和别人拼桌坐着等,服务员拿来茶水,放在了桌子上远离我的那一边,那个陌生人给自己倒完水后竟然主动给我倒水,这样友好的举动出乎意料,当然后来我也主动给他递过调料盘。虽然饺子味道一般,但是吃饭的过程很愉快。如果把济南比作一个姑娘,那么单从外表上来说,北京要比她性感和丰满得多,但我现在还并没有找到真正喜欢北京的理由。就拿倒水这件事来说,都说小概率事件在一次试验中不可能发生,但它发生了,所以就不是小概率事件;而在北京吃饭这么多次,也没碰到过一回,如果我在饭馆主动给同桌的陌生人倒水,碰到和我一样的人知道是友好,没准碰到其他少数人还可能认为我是主动犯贱。北京吸引人的地方主要有两点,除了繁华的外表,就是它悠久的历史文化。历史文化相比我的家乡来说,既不那么悠长又不那么正统,所以这点不吸引我;外表这个东西我认为只是浮云,因为随着时间的变化(这点我们无法阻止),每个人的外表都是会变的,不发达的城市有可能变得发达起来,好看的人也会变得不好看。而北京的繁华,究其原因,好比通过非常手段暴富起来的人一样,容易遭到人的反感和厌恶,而不是羡慕。当然谁都不愿意生活在一个自己没有一点感情投入的地方,也许是我来的时间太短,以后还有许多机会让我去发现这里美好的一面,这也正是我所希望的。比如冷得纯粹的冬天,时常的蓝天白云阳光,这些都比西安要好。《艾玲》里唱过,“迷恋一个人的身体远比爱他的灵魂更加容易”,现在在我看来,有可能恰恰相反。
  既然已经开始工作,自然要考虑一些现实的问题。比较初级的是,先让自己独立起来。独立应该分几个阶段。最早达到的应该是生活上的独立,这个容易理解,其他条件都具备的情况下,自己一个人生活,不至于活着活着就被饿死或者被自己成堆的臭袜子熏死;然后是经济上的独立,经济上独立了,上面所说的“其他条件都具备”才可能实现;然后我觉得是思想上的独立,思想独立了,对于所有的事情你才有自己的思考,真正的看法,折射出来你自己的所有行为,这样别人记住/喜欢/讨厌你的时候可能更多的是因为你的性格而不是你的长相;下来是人格上的独立,思想上独立一段时间后,自然就形成了独立的人格;最后,从理论上,是心的独立。如果把你流放到一个荒岛上,除了生活,你不会因为想念任何人而变得伤感和难过,那么恭喜,你完全没有情感依赖症,应该是达到独立的最高境界了。就我现在的认识,最理想的状态是,人格独立并且能够心灵独立但不做到心的独立。
  还有一个一直在思考的问题,如果我离开了现在的单位,究竟还可以做什么样的事情?这不是说我现在或者将来就不想继续做我现在做的事情或者离开我现在在的单位,只是我觉得如果找到了这个问题的答案,才能够更清楚的认识自己。其实应该是认识到自己的潜力。和小高聊天时候让我又一次想到了这个问题,不过思来想去,对于我这样从来没有远大抱负的人来说,不把自己逼到那一步似乎是找不到答案的。希望能早点改变我现在的认识。
  现在我感觉到自己的2010才真正的结束了。
  有趣的是,我们在公元20到21世纪的地球上一起生存。祝大家新年快乐~

Local方式连接时ArcGIS Server ADF程序部署的问题

如果ADF程序用Local方式连接服务,用VS时必需添加Identity。办法是VS中右键单击网站工程,Add ArcGIS Identiy。
如果部署程序的IIS机器和SOM机器是两台机器,则需要注意了。Add ArcGIS Identity对话框中,填写的用户名密码必需在SOM及其的agsusers或agsadmin组中,并且这里不能勾选加密选项。因为Add ArcGIS Identity工具使用的machine specific(开发机器)的DataProtectionConfigurationProvider方法加密,而这样的话在IIS机器上是无法识别这个加密串的。如果在Add ArcGIS Identity对话框中勾选了加密选项,而后将程序部署到了另外的IIS机器上,则可能出现以下错误:
image未能使用提供程序“DataProtectionConfigurationProvider”进行解密。
解决办法是改用RSAProtectedConfigurationProvider加密办法。如果要在开发机器上加密,则需要导出custom RSA key container为xml文件,在IIS机器上还需要导入之,并且在aspx页面中也需要添加代码才行,具体步骤见:http://msdn.microsoft.com/en-us/library/2w117ede.aspx。如果只要求加密,不追究加密细节的话,可以采用一种简便办法,就是将明文的Identity拷贝到IIS机器上后,用命令行来完成RSA加密过程。步骤如下:
1、右键网站工程,Add ArcGIS Identity。填写SOM机器上的至少在agsusers组中的成员账户,机器名指定IIS机器名(IIS机器上需要创建同样的账户)。如果是域用户,则指定域名;
2、不要勾选加密选项,点击OK。此时web.config里identity节点的用户名密码是明文保存的;
3、拷贝程序文件夹到IIS机器上,建立虚拟目录,转成应用程序,赋予执行脚本权限,使用ArcGIS的应用程序池。此时浏览网站应该是正常的。如果提示地图控件没有primary map resource,确保你的服务在SOM机器上正常工作,然后关掉SOM机器的防火墙;
4、用命令行进行加密。cmd方式到WINDOWSMicrosoft.NetFrameworkv2.0.*目录,运行以下命令:
aspnet_regiis -pe "system.web/identity" -app "/WMA"
其中WMA是IIS中应用程序的名称。
此时查看该网站的web.config文件,identity节点已被加密。并且程序可以正常访问。

参考:http://help.arcgis.com/en/sdk/10.0/serveradf_net/conceptualhelp/index.html#//0002000000w4000000