ArcGIS API for Silverlight开发入门

你用上3G手机了吗?你可能会说,我就是喜欢用nokia1100,ABCDEFG跟我 都不要紧。但你不可否认3G是一种趋势,最终咱们每一个人都会被包裹在3G网络中。1100也不是一成不变,没准哪天为了打击犯罪,会在你的1100上强制 装上GPS。GIS工做既然创建在计算机的基础上,固然也得随着IT行业与时俱进。
       看看如今计算机应用的趋势吧。云(计算),这个东西可讲不清楚,由于云嘛,飘忽不定的。不过能够这样来看它,之后计算机网络上就有一坨(或者几坨)万能的 云,有什么需求云均可以知足咱们,包括各类资源或者计算工做,就不须要在本身的机器上安装任何软件了(甚至操做系统均可以由天边那朵云来提供给你)。更具 体点,SaaS(Software as a Service),各类的网页邮件系统,google docs(一 个在线的office)都是SaaS。收发邮件登录一个网页就行,而不须要在本身机器上安装一个软件。这就是计算机应用的一个趋势,把全部东西都作到网 上。再来看看网上的趋势:RIA(Rich InternetApplication)。RIA简单来说就是一个网页(网络应用),在完成基本功能的同时,会让你以为很漂亮,操做起来很舒服,效果很 炫,而不是打开后马上就想关掉它。其实大受欢迎的开心网(各类插件)和twitter,甚至QQ空间等,都有RIA的身影。
       好了,ArcGIS之因此在行业领先,特色之一就是它能紧跟计算机发展的趋势。ArcGIS Online就是那朵天边的浮云;JavaScript API,Flex API,Siverlight API就是ArcGIS本身RIA的三驾马车。
       这里还得插一句,我以为ArcGIS Server的主角原本是ADF,经过它咱们能够完成一个无所不能的ServerGIS。但在大多数状况下,GIS都是做为特定的业务嵌入在一些MIS中 的,相比购买ADF这辆悍马来讲,仍是直接驾驭三套车跑的更轻快一些。
       如今看看咱们的主角。实际上是ArcGIS API forSilverlight/WPF(如下专一Siverlight部分),那么Silverlight和WPF的关系如何呢?Silverlight 原来叫WPF/E,E就是Everywhere,从命名能够看出它们的关系:Silverlight是WPF的一个子集。WPF 是.NETFramework 3.0的组成部分之一,微软视其为下一代用户界面,总之很高档就是了(在Vista和Windows7中看到的大量与XP不一样的界面,就是WPF的身 影);Silverlight能够看作是WPF在浏览器里的一个外挂,用于向网络用户展现本身的强大能力,因为受限于网络环境,因此是WPF的一部分核心 功能。Siverlight的设计初衷是跨平台,跨浏览器的。
       若是这些仍是比较抽象,那么能够造一个排比句来进一步说明。以前先确定一点,Flash如今在网络中的的主导地位。开始造句。Adobe有Flash,微 软有Silverlight;Adobe有AIR,微软有WPF;Flex有mxml,Silverlight有xaml;Adobe有 ActionScript,微软有Code-Behind(C#/VB.NET)或者JavaScript;Adobe有CS(包括 Dreamweaver,Flash,Fireworks,Photoshop,Illustrator),微软有ExpressionStudio(包 括Blend,Web,Design,Media,Encoder)。如今,可以看来Siverlight究竟是何方神圣了吧?
       最后再来讲说ArcGIS这三驾马车(JavaScript API,Flex API,SiverlightAPI)。国外有人说,随着Siverlight API的推出,与Flex API一块儿,将会使JavaScriptAPI慢慢退出历史舞台,由于前二者就是为RIA而生的。但其实也否则,随着Google和Mozilla工程师 的推动,他们可以使JavaScript的执行速度提升很是多,Chrome就是例子。在这种背景下,一些很是cool的程序员会让古老的JavaScript得到重生。到底哪匹马跑得更快?别回答这种问题,赶忙挑一匹本身的马儿,快马扬鞭吧~~
       在今年的ESRI开发用户大会上,一阵鼓声事后,ESRI隆重推出了ArcGIS API for Silverlight/WPF(beta)。接下来我将把本身在学习Silverlight API中的一些经历和你们分享,与大伙共同进步。javascript

原做者:diligentpig php

原文地址:http://bbs.esrichina-bj.cn/ESRI/thread-43923-1-1.htmlcss

 

ArcGIS API for Silverlight开发入门(1):Getting Started

   这一节来对Silverlight API(ArcGIS API for Silverlight,下同)的开发有个整体的认识。
        欲善其事先利其器。要作开发,第一步就得搭建环境。由于是在 Siverlight基础上作开发,因此先得整理好Siverlight的开发环境。Silverlight并无内建在VS2008中,而是做为add-on的形式附加的。在 这里能够找到详细的安装步骤:
1.jpg
        说明一下,步骤1安装了Silverlight add-on(要求有IDE的SP1补丁包);步骤2安装的是ExpressionStudio中的ExpressionBlend,这个工具至关于可视 化的xaml编辑器,能够用来轻松的建立Silverlight程序的用户界面;步骤3中安装的是Silverlight一种很是华丽的图片处理效果,可 以参看这里的 实例;步骤4包括一些可用的Silverlight控件和例子。接下来再去看看 Silverlight API的要求。能够看出对于开发ArcGIS Silverlight程序来讲,只有步骤1是必须的,其余都是可选的。以后须要从ESRI网站 下载Silverlight API(须要免费注册一个ESRI Global帐户),以备后用。
        总结一下最多见的安装步骤:一、安装VS2008;二、安装 VS2008 SP1;三、安装 Silverlight Tools for Visual Studio 2008 SP1。到此,就可进行Silverlight程序的开发了。关于开发环境的搭建,还能够参考 yyilyzbc版主的帖子。(作Silverlight API的开发不须要在本身的机器上安装ArcGIS Server,可直接使用ArcGIS Online上的数据;但若是要添加本身的数据,固然仍是须要ArcGIS Server了)
        下面就来一个Hello World吧,对于GIS来讲,理所固然就是展现一张漂亮的世界地图了。具体步骤以下:
一、VS2008中,新建project,选择Silverlight Application;
二、 在出现的提示框中选择Add a new ASP.NET Web project to the solution to hostSilverlight;(Silverlight程序与flash同样,至关于网页中的一个插件。第一个选项是将Silverlight嵌入到 一个ASP.NET网站中,第二个选项是将Silverlight嵌入到一个临时的html页面中)
三、添加Silverlight API的引用:与.NET程序开发同样,add reference(注意是在Silverlight工程上而不是ASP.NET工程上),找到从ESRI下载的API,选择添加ESRI.ArcGIS.dll;
四、打开Page.xaml,在UserControl标签中添加一句引用,在Grid标签之间添加一些代码,完成后看起来像这样:
  1. <UserControl x:Class="SilverlightApplication1.Page"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:esri="clr-namespace:ESRI.ArcGIS;assembly=ESRI.ArcGIS"
  5. Width="400" Height="300">
  6. <Grid x:Name="LayoutRoot" Background="White">
  7. <esri:Map x:Name="mymap">
  8.    <esri:Map.Layers>
  9.        <esri:ArcGISTiledMapServiceLayer ID="layerworldmap"
  10.       Url="http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_Imagery_World_2D/MapServer" />
  11.    </esri:Map.Layers>
  12. </esri:Map>
  13. </Grid>
  14. </UserControl>
复制代码
五、按F5,运行程序,就完成了咱们的hello world in
GIS能够在浏览器中看到下面的画面:
2.jpg
        看到效果以后,再来对它进行理解吧。
        先说下Silverlight的程序的基本背景。page.xaml其实是一个控件,至关于asp.net中的default.aspx,大部分 的工做都在这里面完成(app.xaml至关于global.asax);上面的是xaml(读:[ig`zeml])代码,是微软针对 wpf/silverlight的标记语言,与flex中的mxml相似。Silverlight程序中全部的布局工做都是由xaml来完成 的;Silverlight2中,VS2008能够实时对xaml的效果作预览,可是这个预览效果是只读的,对于预览中的控件也不可选;为了弥补这个缺 陷,能够用前面提到的ExpressionBlend来可视化地设计程序界面,会自动生成对应的xaml代码,使用于复杂的布局和美化工做(可参考 Silverlight中的clock例子);再看page.xaml。usercontrol标签(页面的根元素)证实了page.xaml其实是一 个控件类;下面的几句至关于引入了xml的特定命名空间,里面包括了咱们的ESRI.ArcGIS;width和height指明了 Silverlight控件自己的尺寸,通常咱们将这里的width和height属性去掉,已达到全屏的效果(你也能够试试哦);Grid标签是布局控 件,至关于html中的表格,能够进行灵活的页面布局,xaml中经常使用的布局控件还有Canvas和StackPanel;每个xaml的 Control均可以有一个x:Name属性,以便在code-behind页面中对其引用。
        以后是咱们的主角了。Map标签(继承自xaml的Control)至关于一个Map控件,能够在其中加入图层;这里咱们添加了一个 ArcGISTiledMapServiceLayer图层(在后面的文章中会专门讲到SilverlightAPI中的图层类型),对应使用的是 ArcGIS Server发布的通过cache的服务,做为客户端的API,同JavaScript与FlexAPI同样,都是经过REST方式对资源和操做进行引用 的;对这个图层,赋予了一个ID属性,由于SilverlightAPI中的图层是从xaml中的DependencyObject继承而来,因此没有 x:Name的属性,为了方便在code-behind(与asp.net相似的托管代码)的代码中找到这个图层,便使用了ID属性;URL的内容即是 ArcGIS Online发布好的一个世界地图资源。
        到此,应该对这个例子理解的差很少了。若是还想再添加一个图层怎么办呢?没错,就是在Map标签中再添加一个layer,不过要注意的是,第一个加入的图层会显示在最下面,而且决定了整个Map控件的空间参考信息。
        你们天然会想到叠加一个本身的数据图层来看看效果,因而对Map标签内容作了修改(china是本机发布的一个中国地图):
  1. <esri:ArcGISDynamicMapServiceLayer ID="chinamaplayer"
  2.           Url="http://localhost/ArcGIS/rest/services/china/MapServer" />
复制代码
运行后却仍是只有世界地图一个图层(已经确保拼写、大小写正确),怎么回事呢?来用事件帮助查找错误吧。
        Silverlight可以利用.net的一些核心库内容,包括事件。来对刚才的那个图层添加一个事 件:InitializationFailed,当图层添加失败的时候会出发这个事件。添加这个事件的处理也很是简单:在上面的图层中加入 InitializationFailed属性,会提示你生成新的eventhandler,默认回车,看上去像这样:
  1. <esri:ArcGISDynamicMapServiceLayerID="chinamaplayer"InitializationFailed="ArcGISDynamicMapServiceLayer_InitializationFailed"
  2.           Url="http://localhost/ArcGIS/rest/services/china/MapServer" />
复制代码
在事件上面右键单击,Navigate to Event Handler,就会进入前面所说的code-behind页面(本例为C#),添加如下代码:
  1. private void ArcGISDynamicMapServiceLayer_InitializationFailed(object sender, EventArgs e)
  2.       {
  3.           ESRI.ArcGIS.Layer layer = sender as ESRI.ArcGIS.Layer;
  4.           MessageBox.Show(layer.InitializationFailure.Message);
  5.       }
复制代码
而后运行程序,会获得初始化图层失败的缘由:
3.jpg
        原来,为了安全缘由考虑,同flash同样,Silverlight对跨域访问也作了严格的限制。要解决这个问题,能够参考帮助中的说明,将两个 xml文件保存在网站根目录,好比C:\Inetpub\wwwroot中便可(其实保存其中一个就能够了,ArcGISOnline已经将两个xml文 件都放在了网站根目录中,因此咱们能够引用上面的服务)。
        看下最后的效果吧。
4.jpg


        为了更好的理解xaml和Silverlight,建议首先独立完成Silverlight帮助中的两个workthrough:hello worldclock
原文地址:http://bbs.esrichina-bj.cn/ESRI/thread-44042-1-1.htmlhtml

原做者:diligentpig java

 

ArcGIS API for Silverlight开发入门(2):一个基础地图实例

   这节在一个地图实例的基础上,来对Silverlight API中的一些基本概念作一个整体了解,顺便熟悉一下Silverlight的开发知识。
         点击这里,直接看效果。

extendedmap.png
        根据上一节的知识,能够知道这个Silverlight程序里包含了一个Map控件,而且里面至少有一个WorldImagery的图层。那么Page.xaml里的关键代码开起来应该是这样的:
  1. <Grid x:Name="LayoutRoot">
  2. <esri:Map x:Name="Map1">
  3. <esri:Map.Layers>
  4. <esri:ArcGISTiledMapServiceLayer ID="WorldImageLayer" x:Name="WorldImageLayer" Initialized="WorldImageLayer_Initialized"
  5. Url="http://services.arcgisonline.com/ArcGIS/rest/services/ESRI_Imagery_World_2D/MapServer" />
  6. </esri:Map.Layers>
  7. </esri:Map>
  8. </Grid>
复制代码
所 有的布局工做都在一个Grid中进行,给它起个名字叫LayoutRoot。Grid里面放了一个esri:Map元素(Map控件),它继承自 Silverlight的Control,因此拥有Width和Height属性,默认是Auto,自动填充整个Grid。Map.Layers是一个集 合,能够往里面添加layer,这里的layer指的是ArcGIS Server或其余软件发布的地图服务,目前SilverlightAPI中支持的可以直接使用的有 ArcGISDynamicMapServiceLayer,ArcGISTiledMapServiceLayer,ArcGISImageServiceLayer, 分别对应ArcGIS Server发布的动态地图服务,缓存地图服务(两种Map Service)和ImageService,这三种图层是拿来即用的,若是你想加入别的地图服务,好比WMS服务,则须要本身继承相应类型的的 Layer;此外还有GraphicsLayer,ElementLayer,SilverlightAPI特有的FeatureLayer等。这些都会 在以后的小节中讲到。强调一下,与ADF开发里MapResourceManager同样,在Map中加入的内容其实是地图服务,但当作一个layer 处理。
        下面就对这个例子中的每一部分来作说明(与上图中的序号相对应)。

一、当地图移动时获取地图范围。
        当地图范围改变后,显示出当前地图范围的边界值。
        这部分的页面布局是这样的:
  1. <Grid x:Name="Gridright" Margin="0,15,20,0" HorizontalAlignment="Right" VerticalAlignment="Stretch">
  2. <!--extent-->
  3. <Canvas Width="215" Height="110" VerticalAlignment="Top">
  4. <Rectangle Style="{StaticResource rectBottom}" />
  5. <Rectangle Style="{StaticResource rectMiddle}" />
  6. <Rectangle Style="{StaticResource rectTop}" />
  7. <TextBlock x:Name="TBextent" Margin="20,15,15,0" Text="范围:" TextWrapping="Wrap" FontWeight="Bold" />
  8. </Canvas>
  9. </Grid>
复制代码
有 关xaml中详细的布局知识请你们参照其余例子学习,这里稍做讲解。外面的Gridright这个Grid就是页面右边一、二、三、6的父容器,之因此不 用StackPanel是由于6须要贴着页面底部,StackPanel中的元素都会flow贴到一块儿。三个矩形组合便构成了总体轮廓,因为它们都在一个 Canvas中,因此会产生压盖效果。最早加入的rectBottom这个矩形即是最底下的阴影效果,中间的矩形是蓝色框,最上面的矩形是白色的文字显示 区域。“{ }”里的内容在xaml中称做markupextention,StaticResource是使用在别处已经定义好的资源(resource)来对本元 素的一些属性进行自动赋值,这里用来修饰Rectangle的外观。xaml中除了StaticResource这种markupextention以外 还有Binding和TemplateBinding两种markup extention,分别用于数据绑定(databinding)和自定义control的外观。上面的StaticResource是在 App.xaml中定义的,这样就能够在本工程的任何页面中使用,固然也能够定义为LayoutRoot这个Grid的Resource。贴出来你们一看 就明白了:
  1.         <Application.Resources>
  2.         <Style x:Key="rectBottom" TargetType="Rectangle">
  3.             <Setter Property="RadiusX" Value="10" />
  4.             <Setter Property="RadiusY" Value="10" />
  5.             <Setter Property="Fill" Value="#22000000" />
  6.             <Setter Property="Canvas.Left" Value="5" />
  7.             <Setter Property="Canvas.Top" Value="5" />
  8.             <Setter Property="Width" Value="215" />
  9.             <Setter Property="Height" Value="110" />
  10.         </Style>
  11.         <Style x:Key="rectMiddle" TargetType="Rectangle">
  12.             <Setter Property="RadiusX" Value="10" />
  13.             <Setter Property="RadiusY" Value="10" />
  14.             <Setter Property="Fill" Value="#775C90B2" />
  15.             <Setter Property="Canvas.Left" Value="0" />
  16.             <Setter Property="Canvas.Top" Value="0" />
  17.             <Setter Property="Width" Value="215" />
  18.             <Setter Property="Height" Value="110" />
  19.             <Setter Property="Stroke" Value="Gray" />
  20.         </Style>
  21.         <Style x:Key="rectTop" TargetType="Rectangle">
  22.             <Setter Property="RadiusX" Value="5" />
  23.             <Setter Property="RadiusY" Value="5" />
  24.             <Setter Property="Fill" Value="#FFFFFFFF" />
  25.             <Setter Property="Canvas.Left" Value="10" />
  26.             <Setter Property="Canvas.Top" Value="10" />
  27.             <Setter Property="Width" Value="195" />
  28.             <Setter Property="Height" Value="90" />
  29.             <Setter Property="Stroke" Value="DarkGreen" />
  30.         </Style>
  31.     </Application.Resources>
复制代码
它们就至关于网页中的css。若是不使用StaticResource,那么三个矩形看起来应该是这样的:
  1. <Rectangle RadiusX="10" RadiusY="10" Fill="#22000000" Canvas.Left="5" Canvas.Top="5" Width="215" Height="110" />
  2. <Rectangle RadiusX="10" RadiusY="10" Fill="#775C90B2" Canvas.Left="0" Canvas.Top="0" Width="215" Height="110" Stroke="Gray" />
  3. <Rectangle RadiusX="5" RadiusY="5" Fill="#FFFFFFFF" Canvas.Left="10" Canvas.Top="10" Width="195" Height="90" Stroke="DarkGreen" />
复制代码
你猜的没错,在其余矩形框部分也使用到了这些属性。经过实践能够感觉到,xaml中的布局在通常使用中比html+css的布局要简单和灵活许多。好了,继续。
        Map控件里面已经封装了一些事件来供咱们使用,咱们能够在须要的时候捕获它们来进行处理。若是作过ArcGIS产品的二次开发,你应该已经想到我 们要捕获的就是Map的ExtentChanged事件;而要在地图移动或者缩放的过程当中也实时显示地图范围,则还要对ExtentChanging事件 作处理。细心的你可能已经发现,在上面的xaml代码中已经对世界地图这个图层的Initialized事件添加了一个 hanlder:WorldImageLayer_Initialized。固然能够像这样同样给Map的这两个事件添加handler,但这里并不这么 作,而是在世界地图图层的Initialized事件里来绑定它们(移动地图时出发ExtentChanged事件,网速过慢致使图层并未加入到Map 中,则会报错)。来看看Page.xaml.cs中的code-behind代码:
  1. private void WorldImageLayer_Initialized(object sender, EventArgs e)
  2. {
  3. Map1.ExtentChanged += new EventHandler<ESRI.ArcGIS.ExtentEventArgs>(Map1_ExtentChange);
  4. Map1.ExtentChanging += new EventHandler<ESRI.ArcGIS.ExtentEventArgs>(Map1_ExtentChange);
  5. }
复制代码
没错,把两个事件绑定到同一个handler便可。再看看Map1_ExtentChange中的代码:
  1. private void Map1_ExtentChange(object sender, ESRI.ArcGIS.ExtentEventArgs e)
  2. {
  3. TBextent.Text = string.Format("地图范围:\nMinX:{0}\nMinY:{1}\nMaxX:{2}\nMaxY:{3}",
  4. e.NewExtent.XMin, e.NewExtent.YMin, e.NewExtent.XMax, e.NewExtent.YMax);
  5. }
复制代码
很简单吧?顺便提一下,ExtentEventArgs里既然有NewExtent,固然就有OldExtent了,经过比较这两个变量就能够分析出当前进行的是放大、缩小仍是平移操做了。其实还有个更简单的办法,查查看Map的Resolution属性吧。
对于Silverlight API中内容,是否是感受很容易呢(固然你得作够xaml的功课才行)?那么赶快来看第二部分。

二、当鼠标移动时获取鼠标坐标。
        包括屏幕坐标和地图坐标。外观样式方面是这样的:
  1. <!--mouse coords-->
  2. <Canvas Width="215" Height="110" Margin="0,120,0,0" VerticalAlignment="Top">
  3. <Rectangle Style="{StaticResource rectBottom}" />
  4. <Rectangle Style="{StaticResource rectMiddle}" />
  5. <Rectangle Style="{StaticResource rectTop}" />
  6. <StackPanel Orientation="Vertical" Margin="20,15,15,0">
  7. <TextBlock x:Name="TBscreencoords"
  8. HorizontalAlignment="Left" VerticalAlignment="Center" Text="屏幕坐标:" TextWrapping="Wrap" FontWeight="Bold" />
  9. <TextBlock x:Name="TBmapcoords"
  10. HorizontalAlignment="Left" VerticalAlignment="Center" Text="地图坐标:" TextWrapping="Wrap" FontWeight="Bold" />
  11. </StackPanel>
  12. </Canvas>
复制代码
那 么接下来要捕捉那个事件呢?固然就是MouseMove啦。不过若是查看SilverlightAPI中的Map类,发现并无这个事件。但要记住Map 是继承自xaml中的Control,Control继承自FrameworkElement,FrameworkElement继承自 UIElement,这里就有一个MouseMove事件了。因此Map控件的MouseMove是xaml中而不是Siverlight API中的事件(固然整个SilverlightAPI都是创建在xaml基础上的)。在esri:Map标签中添加一个MouseMove事件 (MouseMove="Map1_MouseMove"),来看看code-behind代码:
  1. private void Map1_MouseMove(object sender, MouseEventArgs e)
  2. {
  3. if (Map1.Extent != null)
  4. {
  5. System.Windows.Point screenPnt = e.GetPosition(Map1);
  6. TBscreencoords.Text = string.Format("屏幕坐标:\nX:{0},Y:{1}", screenPnt.X, screenPnt.Y);
  7. ESRI.ArcGIS.Geometry.MapPoint mapPnt = Map1.ScreenToMap(screenPnt);
  8. TBmapcoords.Text = string.Format("地图坐标:\nX:{0}\nY:{1}", Math.Round(mapPnt.X, 4), Math.Round(mapPnt.Y, 4));
  9. }
  10. }
复制代码
可 以看到Map控件提供了屏幕与地图坐标之间转换的方法,比如开发人员的一座桥梁,用来往返于Silverlight特性与地图之间,很是方便。须要说明的 是,这里GetPosition(Map1)得到的屏幕坐标是相对于Map控件的,而不是显示器的左上角。ok,继续来看第三部分。

三、Map里的动画效果。
        当地图放大和平移时均可以看到平滑的效果,这归功于Silverlight的动画功能。Map在封装完动画效果后,给了咱们两个属性来对它们进行设 置:PanDuration和ZoomDuration,用于设置这两个动做持续的时间。它们都是TimeSpan类型的变量,合理的设置能够带来良好的 用户体验。看看这部分的布局:
  1. <!--map animation slider-->
  2. <Canvas Width="215" Height="130" Margin="0,240,0,0" VerticalAlignment="Top">
  3. <Rectangle Style="{StaticResource rectBottom}" Height="130" />
  4. <Rectangle Style="{StaticResource rectMiddle}" Height="130" />
  5. <Rectangle Style="{StaticResource rectTop}" Height="110" />
  6. <StackPanel Orientation="Vertical" Margin="20,15,15,0">
  7. <TextBlock HorizontalAlignment="Left" Text="设置地图缩放动做持续时间:" TextWrapping="Wrap" FontWeight="Bold" />
  8. <TextBlock x:Name="TBzoomdurationvalue" HorizontalAlignment="Left" Text="当前值:" TextWrapping="Wrap" FontWeight="Bold" />
  9. <Slider x:Name="sliderzoomanimation" Orientation="Horizontal" Minimum="0" Maximum="20" SmallChange="1"
  10. LargeChange="5" Cursor="Hand" ValueChanged="slideranimation_ValueChanged" Width="180" />
  11. <TextBlock HorizontalAlignment="Left" Text="设置地图平移动做持续时间:" TextWrapping="Wrap" FontWeight="Bold" />
  12. <TextBlock x:Name="TBpandurationvalue" HorizontalAlignment="Left" Text="当前值:" TextWrapping="Wrap" FontWeight="Bold" />
  13. <Slider x:Name="sliderpananimation" Orientation="Horizontal" Minimum="0" Maximum="20" SmallChange="1"
  14. LargeChange="5" Cursor="Hand" ValueChanged="slideranimation_ValueChanged" Width="180" />
  15. </StackPanel>
  16. </Canvas>
复制代码
主要用到了两个slider控件。再看看拖动滑块时的事件代码,为了省事,这两个事件也用了同一个handler:
  1. private void slideranimation_ValueChanged(object sender, RoutedPropertyChangedEventArgs e)
  2. {
  3. Slider s=sender as Slider;
  4. if (s.Name == "sliderzoomanimation")
  5. {
  6. Map1.ZoomDuration = new TimeSpan(0, 0, Convert.ToInt32(sliderzoomanimation.Value));
  7. TBzoomdurationvalue.Text = string.Format("当前值:{0}秒", Convert.ToInt32(sliderzoomanimation.Value));
  8. }
  9. else
  10. {
  11. Map1.PanDuration = new TimeSpan(0, 0, Convert.ToInt32(sliderpananimation.Value));
  12. TBpandurationvalue.Text = string.Format("当前值:{0}秒", Convert.ToInt32(sliderpananimation.Value));
  13. }
  14. }
复制代码
对应着地图效果,应该很容易理解。继续第四部分。

四、对地图服务可见性与动态地图服务中图层可见性的控制。
        仍是要强调一下,WorldImagery和StreetMap两个能看到的地图实际上都是地图服务,看成layer加入到了Map控件中;而动态 地图服务USA中的图层Cities,Rivers,States才是与ArcMap中图层相对的概念。对于WorldImagery和 StreetMap之间的切换,主要用到了Silverlight API里Layer的
Visible属性;而动态服务中图层可见性的操做,主要是对ArcGISDynamicMapServiceLayer的VisibleLayers数组作了设置。
        StreetMap这个服务其实一开始就加入了地图(在esri:Map标签中):
  1. <esri:ArcGISTiledMapServiceLayer ID="StreetMapLayer"
  2. Url="http://services.arcgisonline.com/ArcGIS/rest/services/ESRI_StreetMap_World_2D/MapServer" Visible="False" />
复制代码
而设置了Visible="False"。图层不可见时地图不会对它作任何处理,因此不用担忧会耗费流量或加剧程序负担。
        看看布局部分:
  1. <StackPanel HorizontalAlignment="Left" Margin="20,15,0,0">
  2. <Canvas x:Name="Canvasleft" Width="165" Height="90" HorizontalAlignment="Left" VerticalAlignment="Top">
  3. <Rectangle Style="{StaticResource rectBottom}" Width="165" Height="90" />
  4. <Rectangle Style="{StaticResource rectMiddle}" Fill="#7758FF00" Width="165" Height="90" />
  5. <Rectangle Style="{StaticResource rectTop}" Width="145" Height="70" />
  6. <!--change layer-->
  7. <StackPanel Margin="20,15,15,0">
  8. <TextBlock Text="切换图层:" TextWrapping="Wrap" FontWeight="Bold" />
  9. <StackPanel Orientation="Horizontal">
  10. <ToggleButton x:Name="TBimagery" Content="Imagery" Click="TBimagery_Clicked" Cursor="Hand" />
  11. <ToggleButton x:Name="TBstreetmap" Content="StreetMap" Click="TBstreetmap_Clicked" Cursor="Hand" />
  12. </StackPanel>
  13. <CheckBox Margin="0,5,0,0" x:Name="chkboxDynamicLayer" Content="添加一个动态图层吧" IsChecked="False" Click="chkboxDynamicLayer_Click" Cursor="Hand" />
  14. </StackPanel>
  15. </Canvas>
  16. </StackPanel>
复制代码
这 里使用了ToggleButton,CheckBox和RadioButton都由它派生而来。Silverlight2中的ToggleButton不 能设置Group(一个Group中自动限定同时只能有一个控件处于激活状态),不如Flex里的ToggleButton来的方便,因此code- behind中多作了些工做。固然这里使用RadioButton也是能够的。
  1. private void TBimagery_Clicked(object sender, RoutedEventArgs e)
  2. {
  3. if (TBstreetmap.IsChecked==true)
  4. {
  5. Map1.Layers["WorldImageLayer"].Visible = true;
  6. Map1.Layers["WorldImageLayer"].Opacity = 0;
  7. TBstreetmap.IsChecked = false;
  8. Storyboard sbworldmapshow = makestoryboard("WorldImageLayer", 0, 1);
  9. Storyboard sbstreetmaphide = makestoryboard("StreetMapLayer", 1, 0);
  10. sbworldmapshow.Begin();
  11. sbstreetmaphide.Begin();
  12. hidelayername = "StreetMapLayer";
  13. timer.Begin();
  14. }
  15. TBimagery.IsChecked = true;
  16. }
  17. private void TBstreetmap_Clicked(object sender, RoutedEventArgs e)
  18. {
  19. if (TBimagery.IsChecked==true)
  20. {
  21. Map1.Layers["StreetMapLayer"].Visible = true;
  22. Map1.Layers["StreetMapLayer"].Opacity = 0;
  23. TBimagery.IsChecked = false;
  24. Storyboard sbstreetmapshow = makestoryboard("StreetMapLayer", 0, 1);
  25. Storyboard sbworldmaphide = makestoryboard("WorldImageLayer", 1, 0);
  26. sbstreetmapshow.Begin();
  27. sbworldmaphide.Begin();
  28. hidelayername = "WorldImageLayer";
  29. timer.Begin();
  30. }
  31. TBstreetmap.IsChecked = true;
  32. }
  33. private void timer_Tick(object sender, EventArgs e)
  34. {
  35. Map1.Layers[hidelayername].Visible = false;
  36. }
  37. public Storyboard makestoryboard(string layername, double from, double to)
  38. {
  39. Storyboard sb = new Storyboard();
  40. ESRI.ArcGIS.ArcGISTiledMapServiceLayer layer = Map1.Layers[layername] as ESRI.ArcGIS.ArcGISTiledMapServiceLayer;
  41. DoubleAnimation doubleAnim = new DoubleAnimation();
  42. doubleAnim.Duration = new TimeSpan(0, 0, 5);
  43. doubleAnim.From = from;
  44. doubleAnim.To = to;
  45. Storyboard.SetTarget(doubleAnim, layer);
  46. Storyboard.SetTargetProperty(doubleAnim, new PropertyPath("Opacity"));
  47. sb.Children.Add(doubleAnim);
  48. return sb;
  49. }
复制代码
当 切换两个地图服务时可以看到一个渐变的效果,这里用到了Silverlight中的动画,它们都是在StoryBoard里面进行的,之后的小节中会讲 Silverlight中的动画,这里再也不废话了,有兴趣的朋友能够本身参考帮助学习。hidelayername是这个一个公用的string变量,用 来在切换的动画效果完成后设置不可见的图层Visible属性。timer也是一个StoryBoard:
  1. <Storyboard x:Name="timer" Completed="timer_Tick" Duration="0:0:5" />
复制代码
这里能够看出把StoryBoard也能巧妙的用做计时器。到了特定时间(5秒)后会自动timer_Tick函数,固然也能够使用.net中的各类timer类。
        下面是添加动态服务的部分。
  1. private void chkboxDynamicLayer_Click(object sender, RoutedEventArgs e)
  2. {
  3. if (chkboxDynamicLayer.IsChecked == true)
  4. {
  5. Map1.Layers.Add(california);
  6. Map1.ZoomTo(california.FullExtent);
  7. if (california.IsInitialized == false)
  8. {
  9. chkboxDynamicLayer.IsEnabled = false;
  10. }
  11. chkboxDynamicLayer.Content = "去掉它";
  12. SVlayers.Visibility = Visibility.Visible;
  13. }
  14. else
  15. {
  16. Map1.Layers.Remove(california);
  17. chkboxDynamicLayer.Content = "添加一个动态图层吧";
  18. SVlayers.Visibility = Visibility.Collapsed;
  19. }
  20. }
  21. private void dynamiclayer_initialized(object s, EventArgs e)
  22. {
  23. //若图层没有初始化好就移除图层,固然会报错了,因此这样作就不会了
  24. chkboxDynamicLayer.IsEnabled = true;
  25. Map1.ZoomTo(california.InitialExtent);
  26. SVlayers.Visibility = Visibility.Visible;
  27. california.ID = "layercalifornia";
  28. ESRI.ArcGIS.ArcGISDynamicMapServiceLayer dynamicServiceLayer = s as ESRI.ArcGIS.ArcGISDynamicMapServiceLayer;
  29. if (dynamicServiceLayer.VisibleLayers == null)
  30. dynamicServiceLayer.VisibleLayers = GetDefaultVisibleLayers(dynamicServiceLayer);
  31. UpdateLayerList(dynamicServiceLayer);
  32. }
复制代码
当添加了动态服务后,会自动弹出一个listbox,固然这些也都是在xaml中定义好的(加在上面的Canvas后面):
  1. <ScrollViewer x:Name="SVlayers" Width="165" Visibility="Collapsed" Height="120">
  2. <ListBox x:Name="LayerVisibilityListBox" >
  3. <ListBox.ItemTemplate>
  4. <DataTemplate>
  5. <CheckBox Margin="2" Name="{Binding LayerIndex}" Content="{Binding LayerName}"
  6. Tag="{Binding ServiceName}" IsChecked="{Binding Visible}"
  7. ClickMode="Press" Click="chkboxToggleVilible_Click" />
  8. </DataTemplate>
  9. </ListBox.ItemTemplate>
  10. </ListBox>
  11. </ScrollViewer>
复制代码
这 里把ListBox放到了ScrollVierwer中,固定了它的高度,当内容过多时能够自动显示纵向滚动条。这里要提一下,ListBox的内容用到 了数据绑定(参考xaml中的DataBinding,有OneTime,OneWay和TwoWay三种模式,这里使用的是默认的OneWay),看起 来里面只有一个CheckBox,但它至关于一个模板,在code-behind中设置了ListBox.ItemSource以后,根据该属性的内容自 动生成多个CheckBox。代码中自定义了一个LayerListData类,它的几个属性分别与上面的CheckBox属性绑定;将一个List赋给 了ListBox.ItemSource,则会自动生成ListBox中的内容。经过一个List类型变量,来控制动态服务的可见图层。代码以下:
  1. public class LayerListData
  2. {
  3. public bool Visible { get; set; }
  4. public string ServiceName { get; set; }
  5. public string LayerName { get; set; }
  6. public int LayerIndex { get; set; }
  7. }
  8. private int[] GetDefaultVisibleLayers(ESRI.ArcGIS.ArcGISDynamicMapServiceLayer dynamicService)
  9. {
  10. List<int> visibleLayerIDList = new List<int>();
  11. ESRI.ArcGIS.LayerInfo[] layerInfoArray = dynamicService.Layers;
  12. for (int index = 0; index < layerInfoArray.Length; index++)
  13. {
  14. if (layerInfoArray[index].DefaultVisibility)
  15. visibleLayerIDList.Add(index);
  16. }
  17. return visibleLayerIDList.ToArray();
  18. }
  19. private void UpdateLayerList(ESRI.ArcGIS.ArcGISDynamicMapServiceLayer dynamicServiceLayer)
  20. {
  21. int[] visibleLayerIDs = dynamicServiceLayer.VisibleLayers;
  22. if (visibleLayerIDs == null)
  23. visibleLayerIDs = GetDefaultVisibleLayers(dynamicServiceLayer);
  24. List<LayerListData> visibleLayerList = new List<LayerListData>();
  25. ESRI.ArcGIS.LayerInfo[] layerInfoArray = dynamicServiceLayer.Layers;
  26. for (int index = 0; index < layerInfoArray.Length; index++)
  27. {
  28. visibleLayerList.Add(new LayerListData()
  29. {
  30. Visible = visibleLayerIDs.Contains(index),
  31. ServiceName = dynamicServiceLayer.ID,
  32. LayerName = layerInfoArray[index].Name,
  33. LayerIndex = index
  34. });
  35. }
  36. LayerVisibilityListBox.ItemsSource = visibleLayerList;
  37. }
  38. void chkboxToggleVilible_Click(object sender, RoutedEventArgs e)
  39. {
  40. CheckBox tickedCheckBox = sender as CheckBox;
  41. string serviceName = tickedCheckBox.Tag.ToString();
  42. bool visible = (bool)tickedCheckBox.IsChecked;
  43. int layerIndex = Int32.Parse(tickedCheckBox.Name);
  44. ESRI.ArcGIS.ArcGISDynamicMapServiceLayer dynamicServiceLayer = Map1.Layers[serviceName] as
  45. ESRI.ArcGIS.ArcGISDynamicMapServiceLayer;
  46. List<int> visibleLayerList =
  47. dynamicServiceLayer.VisibleLayers != null
  48. ? dynamicServiceLayer.VisibleLayers.ToList() : new List<int>();
  49. if (visible)
  50. {
  51. if (!visibleLayerList.Contains(layerIndex))
  52. visibleLayerList.Add(layerIndex);
  53. }
  54. else
  55. {
  56. if (visibleLayerList.Contains(layerIndex))
  57. visibleLayerList.Remove(layerIndex);
  58. }
  59. dynamicServiceLayer.VisibleLayers = visibleLayerList.ToArray();
  60. }
复制代码
五、比例尺。
        Silverlight API提供了一个ScaleBar类,能够方便的设置地图比例尺。
  1. <!--scale bar 放在LayoutRoot Grid中-->
  2. <Canvas HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="10,0,0,20">
  3. <esri:ScaleBar x:Name="scalebar" MapUnit="DecimalDegrees" DisplayUnit="Kilometers" Foreground="Black" FillColor1="White" FillColor2="Blue" />
  4. </Canvas>
复制代码
须要在初始化的时候设置scalebar的Map属性,顺便来看看整个页面的初始化工做:
  1. namespace demo_02_extendedmap
  2. {
  3. public partial class Page : UserControl
  4. {
  5. private ESRI.ArcGIS.ArcGISDynamicMapServiceLayer california = new ESRI.ArcGIS.ArcGISDynamicMapServiceLayer();
  6. private string hidelayername;
  7. public Page()
  8. {
  9. InitializeComponent();
  10. scalebar.Map = Map1;
  11. scalebarstoryboard.Begin();
  12. TBzoomdurationvalue.Text = string.Format("当前值:{0}.{1}秒", Map1.ZoomDuration.Seconds, Map1.ZoomDuration.Milliseconds);
  13. TBpandurationvalue.Text = string.Format("当前值:{0}.{1}秒", Map1.PanDuration.Seconds, Map1.PanDuration.Milliseconds);
  14. california.Url = "http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Specialty/ESRI_StatesCitiesRivers_USA/MapServer";
  15. california.Opacity = 0.5;
  16. california.Initialized += new EventHandler<EventArgs>(dynamiclayer_initialized);
  17. TBimagery.IsChecked = true;
  18. makestoryboard("WorldImageLayer", 0, 1).Begin();
  19. //切换全屏/窗口
  20. Application.Current.Host.Content.FullScreenChanged += new EventHandler(fullscreen_changed);
  21. }
  22. }
  23. }
复制代码
scalebarstoryboard是xaml里自定义的一个动画,效果见比例尺旁的单位。

六、地图相关操做。
        Map控件已经内置了一些键盘鼠标事件,但目前不能像JavascriptAPI中那样禁用这些事件。这里还用到了Silverlight程序的一 个全屏特性,实际上是对Application.Current.Host.Content的一个属性作了设置。直接看代码吧:
  1. <!--operation info-->
  2. <Canvas Width="215" Height="110" Margin="0,0,0,30" VerticalAlignment="Bottom">
  3. <Rectangle Style="{StaticResource rectBottom}" />
  4. <Rectangle Style="{StaticResource rectMiddle}" Fill="#77FF0000" />
  5. <Rectangle Style="{StaticResource rectTop}" />
  6. <TextBlock Margin="20,15,15,0" TextWrapping="Wrap"
  7. Text="地图操做提示:双击放大 Shift+拖拽:放大到指定范围 Ctrl+Shift+拖拽:缩小到指定范围" />
  8. <ToggleButton x:Name="TBfullscreen" Content="点击切换地图全屏" HorizontalAlignment="Center" Canvas.Left="100" Canvas.Top="15" Height="30" Click="TBfullscreen_Click" />
  9. </Canvas>
复制代码
放到Gridright Grid中,
  1. private void TBfullscreen_Click(object sender, RoutedEventArgs e)
  2. {
  3. System.Windows.Interop.Content content = Application.Current.Host.Content;
  4. content.IsFullScreen=!content.IsFullScreen;
  5. }
  6. private void fullscreen_changed(object o,EventArgs e)
  7. {
  8. System.Windows.Interop.Content content=Application.Current.Host.Content;
  9. TBfullscreen.IsChecked = content.IsFullScreen;
  10. }
复制代码
七、进度条。
        最后还剩下地图中的这个进度条。利用了Map控件内置的一个Progress事件。
  1. <!--progressbar 放在LayoutRoot中-->
  2. <Grid HorizontalAlignment="Center" x:Name="progressGrid" VerticalAlignment="Center" Width="200" Height="20" Margin="5,5,5,5">
  3. <ProgressBar x:Name="MyProgressBar" Minimum="0" Maximum="100" />
  4. <TextBlock x:Name="ProgressValueTextBlock" Text="100%" HorizontalAlignment="Center" VerticalAlignment="Center" />
  5. </Grid>
复制代码
在esri:Map标签中加入一个事件:Progress="Map1_Progress",
  1. private void Map1_Progress(object sender, ESRI.ArcGIS.ProgressEventArgs e)
  2. {
  3. if (e.Progress < 100)
  4. {
  5. progressGrid.Visibility = Visibility.Visible;
  6. MyProgressBar.Value = e.Progress;
  7. ProgressValueTextBlock.Text = String.Format("正在处理 {0}%", e.Progress);
  8. }
  9. else
  10. {
  11. progressGrid.Visibility = Visibility.Collapsed;
  12. }
  13. }
复制代码
好了到此就已经讲完了整个地图功能。尽管想尽量详细说明每段代码,便于初学的朋友学习,但也不可能面面俱到。没有讲明白的地方你们能够本身思考,查帮助。学习的过程当中,不思考,无进步。
原文地址: http://bbs.esrichina-bj.cn/ESRI/thread-44365-1-1.html
 

ArcGIS API for Silverlight开发入门(3):Widgets

Widgets翻译过来是小玩具。若是使用过Dojo或者ExtJS等js框架确定会了解到这个“小玩具”也有大用处,可以在很大程度上减小咱们的工做量,快速完成功能需求。能减小多大工做量呢?让咱们先来, 点击这里,看一个例子。

031sliderbar.png


 


        前两节的地图中,总感受少点什么……对,就是一个sliderbar,有了它感受就像汽车有了方向盘同样,可以控制方向了。那么来看看实现上面这个例子中的滑块条须要作什么工做吧。
在silverlight中建立一个UserControl,把上面sliderbar的外观和功能都封装在里面。
来看具体工做。vs中,在silverlight工程上右键单击,add,new item,选择silverlight user control,起名叫mapslider,在mapslider.xaml中填以下代码:
  1. <Grid x:Name="slidergrid" HorizontalAlignment="Left" VerticalAlignment="Center" Background="Azure" Margin="20">
  2.         <StackPanel Orientation="Vertical">
  3.             <Button x:Name="btnzoomin" Content="+" Click="btnzoomin_Click" />
  4.             <Slider x:Name="sliderLOD" Orientation="Vertical"  Height="200" SmallChange="1" LargeChange="1"  Minimum="0" Cursor="Hand" ValueChanged="slider1_ValueChanged" />
  5.             <Button x:Name="btnzoomout" Content="-" Click="btnzoomout_Click" />
  6.         </StackPanel>
  7.     </Grid>
复制代码
上 面这些就是滑块条的外观,接下来看功能部分。大体思路是在mapslider类中设置一个公共属性Map,就是须要操做的地图了,但这个属性不是 ESRI.ArcGIS.Map,而是另外一个自定义类。为何要这么作?由于这个自定义类须要实现INotifyPropertyChanged接口,当 咱们把本身的Map控件做为mapslider的属性赋值的时候,这个Map须要作另一些工做。看代码吧,不太明白的话就要增强对 silverlight中data binding的学习。在mapslider.xaml.cs页面中填入一下代码:
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Net;
  5. using System.Windows;
  6. using System.Windows.Controls;
  7. using System.Windows.Documents;
  8. using System.Windows.Input;
  9. using System.Windows.Media;
  10. using System.Windows.Media.Animation;
  11. using System.Windows.Shapes;
  12. using System.ComponentModel;
  13. namespace customcontrol
  14. {
  15.     public partial class mapslider : UserControl
  16.     {
  17.         private mymap map = new mymap();
  18.         public ESRI.ArcGIS.Map Map
  19.         {
  20.             get
  21.             {
  22.                 return map.Map;
  23.             }
  24.             set
  25.             {
  26.                 map.Map=value;
  27.                 if (map.Map != null)
  28.                 {
  29.                     Map.ExtentChanged += new EventHandler<ESRI.ArcGIS.ExtentEventArgs>(map_ExtentChanged);
  30.                     Map.SnapToLevels = true;
  31.                     ((ESRI.ArcGIS.ArcGISTiledMapServiceLayer)Map.Layers[0]).Initialized += new EventHandler<EventArgs>(layer0_initialized);
  32.                 }
  33.             }
  34.         }
  35.         private void layer0_initialized(object o,EventArgs e)
  36.         {
  37.             sliderLOD.Maximum = ((ESRI.ArcGIS.ArcGISTiledMapServiceLayer)Map.Layers[0]).TileInfo.Lods.Length - 1;
  38.         }
  39.         public mapslider()
  40.         {
  41.             InitializeComponent();
  42.         }
  43.         private void slider1_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
  44.         {
  45.             if (map.Map!=null)
  46.             {
  47.                 Map.ZoomToResolution(((ESRI.ArcGIS.ArcGISTiledMapServiceLayer)Map.Layers[0]).TileInfo.Lods[Convert.ToInt32(e.NewValue)].Resolution);
  48.             }
  49.         }
  50.         private void map_ExtentChanged(object o, ESRI.ArcGIS.ExtentEventArgs e)
  51.         {
  52.             ESRI.ArcGIS.ArcGISTiledMapServiceLayer layer = Map.Layers[0] as ESRI.ArcGIS.ArcGISTiledMapServiceLayer;
  53.             int i;
  54.             for (i = 0; i < layer.TileInfo.Lods.Length; i++)
  55.             {
  56.                 if (Map.Resolution == layer.TileInfo.Lods[i].Resolution)
  57.                     break;
  58.             }
  59.             sliderLOD.Value = i;
  60.         }
  61.         private void btnzoomin_Click(object sender, RoutedEventArgs e)
  62.         {
  63.             sliderLOD.Value += 1;
  64.         }
  65.         private void btnzoomout_Click(object sender, RoutedEventArgs e)
  66.         {
  67.             sliderLOD.Value -= 1;
  68.         }
  69.     }
  70.     //执行了这个接口后,当在主页面page.xaml.cs中给Map赋值的时候,就能返到set语句中,以便执行绑定事件的代码
  71.     public class mymap:INotifyPropertyChanged
  72.     {
  73.         private ESRI.ArcGIS.Map map;
  74.         public ESRI.ArcGIS.Map Map
  75.         {
  76.             get{return map;}
  77.             set
  78.             {
  79.                 map = value;
  80.                 if (PropertyChanged!=null)
  81.                 {
  82.                     PropertyChanged(this, new PropertyChangedEventArgs("Map"));
  83.                 }
  84.             }
  85.         }
  86.         public event PropertyChangedEventHandler PropertyChanged;
  87.     }
  88. }
复制代码
作完封装的工做,来看如何在page.xaml中使用这个控件。只须要三行代码:一、注册user control的命名空间(和对Silverlight API的引用是同样的,放在页面中的根元素UserControl里):
xmlns:uc="clr-namespace:customcontrol"
        二、在页面中添加这个slider:
<Grid x:Name="LayoutRoot" Background="White">
        <!--地图在这里-->
        </esri:Map>
        
        <uc:mapslider x:Name="mapslider1"/>
</Grid>
        三、在初始化的时候对咱们自定义控件的Map属性赋值(page.xaml.cs中):
public Page()
      {
          InitializeComponent();
          mapslider1.Map = Map1;
      }
        到此应该有这个感受,封装比较麻烦,但使用封装好的控件很是简便。这就是Widgets带给咱们的好处。目前的beta版 中,SilverlightAPI已经替咱们完成5个Widgets的封装,它们分别 是:Magnifier,ToolBar,BookMark,Navigation,MapTip,其中ToolBar内部使用了 ToolBarItemCollection和ToolBarItem等类。仍是经过一个例子,来看看这几个控件都长什么样吧( 点击这里):

032widgets.png


 



        MapTip须要使用到Query Task,之后的小节中再涉及到。如今分别熟悉一下这几个Widgets的用法。
一、ToolBar和Magnifier:
        这个和ADF开发中的ToolBar(工具条)是同样的,里面能够添加ToolItem(工具),已实现各类功能,好比平移,缩放等。 silverlight中固然要有一些比较好看的效果了,好比把鼠标放在工具条上选择工具的时候,会有放大效果,这个效果是默认的,不能设置;点击一个工 具时,该工具会跳动一下,这个是ToolbarItemClickEffect中的Bounce效果(目前只有Bounce和None两个选择),也是默 认的。此例中ToolBar里面有三个ToolBarItem,分别是Pan,FullExtent和Magnifier(自己也是一个Widget), 下面是ToolBar的布局:
  1. <Grid Height="110" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,10,10,0" >
  2.             <Rectangle Fill="#22000000" RadiusX="10" RadiusY="10" Margin="0,4,0,0" />
  3.             <Rectangle Fill="#775C90B2" Stroke="Gray"  RadiusX="10" RadiusY="10" Margin="0,0,0,5" />
  4.             <Rectangle Fill="#66FFFFFF" Stroke="DarkGray" RadiusX="5" RadiusY="5" Margin="10,10,10,15" />
  5.             <StackPanel Orientation="Vertical">
  6.                 <esriWidgets:Toolbar x:Name="MyToolbar" MaxItemHeight="80" MaxItemWidth="80"
  7.                     VerticalAlignment="Top" HorizontalAlignment="Center"
  8.                     ToolbarItemClicked="MyToolbar_ToolbarItemClicked"
  9.                     ToolbarItemClickEffect="Bounce"
  10.                     Width="250" Height="80">
  11.                     <esriWidgets:Toolbar.Items>
  12.                         <esriWidgets:ToolbarItemCollection>
  13.                             <esriWidgets:ToolbarItem Text="Pan">
  14.                                 <esriWidgets:ToolbarItem.Content>
  15.                                     <Image Source="img/i_pan.png" Stretch="UniformToFill" Margin="5" />
  16.                                 </esriWidgets:ToolbarItem.Content>
  17.                             </esriWidgets:ToolbarItem>
  18.                             <esriWidgets:ToolbarItem Text="Full Screen">
  19.                                 <esriWidgets:ToolbarItem.Content>
  20.                                     <Image Source="img/i_globe.png" Stretch="UniformToFill" Margin="5" />
  21.                                 </esriWidgets:ToolbarItem.Content>
  22.                             </esriWidgets:ToolbarItem>
  23.                             <esriWidgets:ToolbarItem Text="Full Screen">
  24.                                 <esriWidgets:ToolbarItem.Content>
  25.                                     <Image Source="img/magglass.png" Stretch="UniformToFill" Margin="5"
  26.                                            MouseLeftButtonDown="Image_MouseLeftButtonDown"/>
  27.                                 </esriWidgets:ToolbarItem.Content>
  28.                             </esriWidgets:ToolbarItem>
  29.                         </esriWidgets:ToolbarItemCollection>
  30.                     </esriWidgets:Toolbar.Items>
  31.                 </esriWidgets:Toolbar>
  32.                 <TextBlock x:Name="StatusTextBlock" Text="" FontWeight="Bold" HorizontalAlignment="Center"/>
  33.             </StackPanel>
  34.         </Grid>
复制代码
而后是code-behind内容:
private void MyToolbar_ToolbarItemClicked(object sender, ESRI.ArcGIS.Widgets.SelectedToolbarItemArgs e)
        {
            switch (e.Index)
            {
                case 0:
                    //pan
                    break;
                case 1:
                    Map1.ZoomTo(Map1.Layers.GetFullExtent());
                    break;
                case 2:
                    break;
            }
        }

        private void Image_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            MyMagnifier.Enabled = !MyMagnifier.Enabled;
        }
        别忘了在page的构造函数中加一句:MyMagnifier.Initialize(Map1);。能够看出,Pan工具不须要任何代码,由于地 图自己的默认动做就是Pan,而FullExtent也是利用了Map的ZoomTo()。放大镜的工具是在该图片被鼠标左键按住的过程当中激活的(设置 enabled属性),只要鼠标左键没有按住放大镜图片,该Widget就设置为不可用。比较有用的是咱们能够单独设置放大镜本身的图层及放大倍数,这里 放大镜使用的就是StreetMap,倍数为3。
二、BookMark:
        这个功能和ArcMap(9.3版本)中的BookMark是同样的,能够像看书同样,为当前地图范围设置一个书签,便于其余时候快速定位到该范 围。而查看API中的Bookmark.MapBookmark类(能够利用它对书签的内容进行单个添加或删除),能够发现其实每一个书签存储的内容是一个 Extent,而后再起一个名字就能够了。添加了bookmark widget后彷佛会形成vs中的preview窗口出错。
<!--bookmark-->
        <Canvas>
            <esriWidgets:Bookmark x:Name="MyBookmarks" Width="125" HorizontalAlignment="Left" VerticalAlignment="Top"
             Margin="20" Background="#99257194" BorderBrush="#FF92a8b3" Foreground="Black"
             Loaded="MyBookmarks_Loaded" />
        </Canvas>
page.xaml.cs中:
private void MyBookmarks_Loaded(object sender, RoutedEventArgs e)
        {
            MyBookmarks.Map = Map1;
        }
三、Navigation:
        这个导航条工具是目前网络地图必备的一个控件,但silverlight的功能,能够轻易实现地图的旋转(其实也能够在代码中经过 Map.Rotation属性来设置)。经试验这个widget只能放在StackPanel或Grid容器里,若是放在Canvas里的话地图中不会显 示。
<!--navigation bar.must be in a stackpanel-->
        <StackPanel HorizontalAlignment="Left" VerticalAlignment="Bottom">
            <esriWidgets:Navigation x:Name="MyNavigation" Margin="5"  />
        </StackPanel>
        一样在page的构造函数中添加一句:MyNavigation.Map = Map1;。
        API中的Widgets能够简化咱们的工做,拿来即用。但明显的缺陷就是不灵活,若是想使本身的控件不那么千篇一概的话,就须要本身进行开发工做了。
原文地址: http://bbs.esrichina-bj.cn/ESRI/thread-44555-1-1.html
 

ArcGIS API for Silverlight开发入门(4):用户与地理信息之间的桥梁--GraphicsLayer

   咱们与地图交互的过程时刻在进行着:一个拉框放大操做,或者对地图内容的查询等。 这些交互过程当中的输入输出,一般都是反映在独立于地图数据一个“层”上。好比拉框放大,咱们能看见鼠标所画的一个矩形;又好比对兴趣点的查询,结果一般是 将符合条件的兴趣点的形状高亮显示在那个独立的“层”中,经过它既能够反映用户的输入,又能够展示地图的输出。这个“层”就是 GraphicsLayer。
        其实ADF开发中也有GraphicsLayer的概念,一样在其余两个客户端API(JavaScript/Flex)中也能找到GraphicsLayer的身影,它们都是同样同样的。
        本节咱们主要看如何在GraphicsLayer中展示内容。固然第一个工做就是添加ESRI.ArcGIS.dll的引用,引入esri的xml命名空间;接下来在Map中添加一个GraphicsLayer图层:
  1. <esri:Map x:Name="Map1">
  2. <esri:Map.Layers>
  3. <!-- 其余图层 -->
  4. <esri:GraphicsLayer ID="GLayer" />
  5. </esri:Map.Layers>
  6. </esri:Map>
复制代码
要 使GraphicsLayer中的内容处于最顶端(不被其余图层内容覆盖),就要将它放在Map标签里的最下头,像上面那样。从命名咱们不难看 出,GraphicLayer里面放的就是Graphic的集合了。Graphic(ESRI.ArcGIS.Graphic)是 GraphicsLayer中的基本元素,它包括了Geometry(在ESRI.ArcGIS.Geometry命名空间中),Symbol(在 ESRI.ArcGIS.Symbol命名空间中),Attributes等属性。全部显示在地图中的矢量元素都有一个Geometry,里面包含了若干 地理坐标,用于显示地图上地物的形状,它是Point,Polyline,Polygon等的总称,在这里表明了Graphic的形状。Symbol表明 了Graphic的外观,它是一系列符号的总称,咱们一般跟SimpleMarkerSymbol,SimpleLineSymbol和 SimpleFillSymbol等打交道,它们分别对应了上面3种不一样的Geometry(Point,Polyline,Polygon)。
        要让一个Graphic显示出来,总共分3步:
一、定义Graphic:
在xaml中
  1. <esri:Graphic>
  2. </esri:Graphic>
复制代码
在code-behind中
Graphic g= new Graphic()
二、设置Graphic的Geometry和Symbol属性:
在xaml中
  1. <esri:Graphic>
  2. <esri:Graphic.Symbol>
  3. <esriSymbols:SimpleMarkerSymbol Color="Blue" Size="12" Style="Square" />
  4. </esri:Graphic.Symbol>
  5. <esriGeometry:MapPoint X="108" Y="30" />
  6. </esri:Graphic>
复制代码
在code-behind中
  1. Graphic g = new Graphic()
  2. {
  3. Geometry = new MapPoint(108, 30),
  4. Symbol = new SimpleMarkerSymbol()
  5. {
  6. Color = new SolidColorBrush(Colors.Blue),
  7. Size = 12,
  8. Style = SimpleMarkerSymbol.SimpleMarkerStyle.Square
  9. }
  10. };
复制代码
三、把定义好的Graphic添加到GraphicsLayer里:
在xaml中
  1. <esri:GraphicsLayer ID="GLayer">
  2. <esri:GraphicsLayer.Graphics>
  3. <esri:Graphic>
  4. <esri:Graphic.Symbol>
  5. <esriSymbols:SimpleMarkerSymbol Color="Blue" Size="12" Style="Square" />
  6. </esri:Graphic.Symbol>
  7. <esriGeometry:MapPoint X="108" Y="30" />
  8. </esri:Graphic>
  9. </esri:GraphicsLayer.Graphics>
  10. </esri:GraphicsLayer>
复制代码
在code-behind中
  1. Graphic g = new Graphic()
  2. {
  3. Geometry = new MapPoint(108, 30),
  4. Symbol = new SimpleMarkerSymbol()
  5. {
  6. Color = new SolidColorBrush(Colors.Blue),
  7. Size = 12,
  8. Style = SimpleMarkerSymbol.SimpleMarkerStyle.Square
  9. }
  10. };
  11. GraphicsLayer glayer = Map1.Layers["GLayer"] as GraphicsLayer;
  12. glayer.Graphics.Add(g);
复制代码
看一下效果:

04_graphic.png


 


        图中还有其余的图形,无非是改变了Graphic的Geometry和Symbol属性。图上的那只灰熊是一段动画文件,利用Silverlight的特性,可以定义出表现力丰富的各类符号。
        尽管可以彻底在xaml中来完成工做,但仍是建议将可视化元素的定义放在xaml中,将实现的逻辑部分放在code-behind中。看一下添加图中那些Graphic的代码:
  1. <Grid.Resources>
  2. <esriSymbols:SimpleMarkerSymbol x:Name="RedMarkerSymbol" Color="Red" Size="12" Style="Circle" />
  3. <!-- 惋惜目前Silverlight只支持Jpeg和PNG格式的图像,因此PictureMarkerSymbol没法显示GIF格式的图像,不然会报ImagingError的错误 -->
  4. <esriSymbolsictureMarkerSymbol x:Name="PinPictureMarkerSymbol" Source="imgs/pin.png" OffsetX="10" OffsetY="10" />
  5. <esriSymbols:SimpleLineSymbol x:Name="RedLineSymbol" Color="Red" Width="4" Style="Solid" />
  6. <esriSymbols:CartographicLineSymbol x:Name="CartoLineSymbol" Color="Red" Width="10" DashCap="Triangle" LineJoin="Round" DashArray="6,2" />
  7. <esriSymbols:SimpleFillSymbol x:Name="RedFillSymbol" Fill="#66FF0000" BorderBrush="Red" BorderThickness="2" />
  8. </Grid.Resources>
  9. <MediaElement x:Name="BearVideo" />
复制代码
  1. private void AddGraphics()
  2. {
  3. GraphicsLayer glayer = Map1.Layers["GLayer"] as GraphicsLayer;
  4. Graphic[] graphics = new Graphic[8];
  5. graphics[0] = new Graphic()
  6. {
  7. Geometry = new MapPoint(108, 34),
  8. Symbol = RedMarkerSymbol
  9. };
  10. graphics[1] = new Graphic()
  11. {
  12. Geometry = new MapPoint(108, 30),
  13. Symbol = new SimpleMarkerSymbol()
  14. {
  15. Color = new SolidColorBrush(Colors.Blue),
  16. Size = 12,
  17. Style = SimpleMarkerSymbol.SimpleMarkerStyle.Square
  18. }
  19. };
  20. graphics[2] = new Graphic()
  21. {
  22. Geometry = new MapPoint(108, 25),
  23. Symbol = PinPictureMarkerSymbol
  24. };
  25. graphics[3] = new Graphic()
  26. {
  27. Geometry = new MapPoint(108, 20),
  28. Symbol = new TextSymbol()
  29. {
  30. FontFamily = new FontFamily("微软雅黑, 宋体"),
  31. FontSize = 14,
  32. Foreground = new SolidColorBrush(Colors.Black),
  33. Text = "这是text symbol"
  34. }
  35. };
  36. graphics[4] = new Graphic();
  37. graphics[4].Symbol = RedLineSymbol;
  38. ESRI.ArcGIS.Geometry.PointCollection pc = new ESRI.ArcGIS.Geometry.PointCollection()
  39. {
  40. new MapPoint(95,10),
  41. new MapPoint(110,-15),
  42. new MapPoint(130,10)
  43. };
  44. ESRI.ArcGIS.Geometry.Polyline pl = new ESRI.ArcGIS.Geometry.Polyline();
  45. pl.Paths.Add(pc);
  46. graphics[4].Geometry = pl;
  47. graphics[5] = new Graphic();
  48. graphics[5].Symbol = CartoLineSymbol;
  49. ESRI.ArcGIS.Geometry.PointCollection pc1 = new ESRI.ArcGIS.Geometry.PointCollection()
  50. {
  51. new MapPoint(95,0),
  52. new MapPoint(110,-25),
  53. new MapPoint(130,0)
  54. };
  55. ESRI.ArcGIS.Geometry.Polyline pl1 = new ESRI.ArcGIS.Geometry.Polyline();
  56. pl1.Paths.Add(pc1);
  57. graphics[5].Geometry = pl1;
  58. graphics[6] = new Graphic()
  59. {
  60. Symbol = RedFillSymbol
  61. };
  62. ESRI.ArcGIS.Geometry.PointCollection pc2 = new ESRI.ArcGIS.Geometry.PointCollection()
  63. {
  64. new MapPoint(110,-30),
  65. new MapPoint(130,-30),
  66. new MapPoint(130,-45),
  67. new MapPoint(120,-55),
  68. new MapPoint(110,-45),
  69. new MapPoint(110,-30)
  70. };
  71. ESRI.ArcGIS.Geometry.Polygon pg = new ESRI.ArcGIS.Geometry.Polygon();
  72. pg.Rings.Add(pc2);
  73. graphics[6].Geometry=pg;
  74. graphics[7] = new Graphic();
  75. //MediaElement的Name属性只能在xaml中定义(见帮助),因此决定了MediaElement不能彻底在cs代码中定义
  76. BearVideo.Source = new Uri("http://serverapps.esri.com/media/bear.wmv", UriKind.RelativeOrAbsolute);
  77. BearVideo.IsHitTestVisible=false;
  78. BearVideo.IsMuted=true;
  79. BearVideo.AutoPlay=true;
  80. BearVideo.Opacity=0;
  81. ESRI.ArcGIS.Geometry.Polygon pg2 = new ESRI.ArcGIS.Geometry.Polygon();
  82. ESRI.ArcGIS.Geometry.PointCollection pc3 = new ESRI.ArcGIS.Geometry.PointCollection()
  83. {
  84. new MapPoint(10,-20),
  85. new MapPoint(32,7),
  86. new MapPoint(62,-35),
  87. new MapPoint(11,-36),
  88. new MapPoint(10,-20)
  89. };
  90. pg2.Rings.Add(pc3);
  91. graphics[7].Geometry=pg2;
  92. graphics[7].Symbol = new SimpleFillSymbol()
  93. {
  94. Fill = new VideoBrush()
  95. {
  96. SourceName = BearVideo.Name,
  97. Opacity = 0.6,
  98. Stretch = Stretch.UniformToFill
  99. }
  100. };
  101. foreach (Graphic g in graphics)
  102. {
  103. glayer.Graphics.Add(g);
  104. g.MouseLeftButtonDown+=new MouseButtonEventHandler(graphic_MouseLeftButtonDown);
  105. }
  106. }
  107. private void graphic_MouseLeftButtonDown(object o,MouseButtonEventArgs e)
  108. {
  109. Graphic g=o as Graphic;
  110. MessageBox.Show(string.Format("Geometry:{0}\nSymbol:{1}",g.Geometry.GetType().ToString(),g.Symbol.GetType().ToString()));
  111. }
复制代码
可 以看到,彻底可以在一个Graphic上定义一些事件,来达到程序的目的。你们能够试着把上面的内容在xaml中改写一遍。看到这里确定会产生一个疑问: 难道每一个Geometry的定义都这么困难吗?其实SilverlightAPI已经给咱们提供了ESRI.ArcGIS.Draw(继承自xaml中的 Canvas)类,它能很是方便的捕捉到用户的鼠标操做,从而获取各类Geometry来供程序使用。
        能够把Draw理解成一块画板,调用Draw的Active()方法,就能够开始在画板上面绘画,程序会自动记录鼠标画出的每一个Geometry, 调用DeActive()方法,中止绘画。Active()有一个DrawMode参数,它决定了咱们即将在这个画板上画出的内容类 型:Point,Polyline,Polygon等。在画的过程当中咱们能够看到地图上能够实时反映出咱们绘画的内容,而这些则利用了Draw的预约义 Symbol:DefaultMarkerSymbol,DefaultLineSymbol,DefaultPolygonSymbol等。对应关系如 下:

04_drawmode.png


 


        每当完成一个图形的绘制,就会触发Draw.OnDrawComplete事件,利用事件参数就能够得到Geometry,以后能够建立一个 Graphic,设置一个Symbol(通常使用Draw的预约义Symbol),把画好的这个Graphic添加到一个GraphicsLayer中。
         点击这里,查看一个比较完整的Graphics的例子。
最后来看一下这个例子的部分代码:
  1. <Grid.Resources>
  2. <esriSymbols:SimpleMarkerSymbol x:Name="DefaultMarkerSymbol" Color="Red" Size="12" Style="Circle" />
  3. <esriSymbols:CartographicLineSymbol x:Name="DefaultLineSymbol" Color="Red" Width="4" />
  4. <esriSymbols:SimpleFillSymbol x:Name="DefaultFillSymbol" Fill="#33FF0000" BorderBrush="Red" BorderThickness="2" />
  5. <esriSymbols:SimpleFillSymbol x:Name="DefaultPolygonSymbol" Fill="#33FF0000" BorderBrush="Red" BorderThickness="2" />
  6. </Grid.Resources>
  7. <esriraw x:Name="Draw1"
  8. DefaultRectangleSymbol="{StaticResource DefaultFillSymbol}"
  9. DefaultMarkerSymbol="{StaticResource DefaultMarkerSymbol}"
  10. DefaultLineSymbol="{StaticResource DefaultLineSymbol}"
  11. DefaultPolygonSymbol="{StaticResource DefaultPolygonSymbol}"
  12. Loaded="Draw1_Loaded"
  13. OnDrawComplete="Draw1_OnDrawComplete" />
  14. <Canvas VerticalAlignment="Top" HorizontalAlignment="Left" Margin="20,20,0,0" Width="430" Height="110">
  15. <Rectangle RadiusX="10" RadiusY="10" Width="430" Height="110" Fill="#98000000" Stroke="#FF6495ED" />
  16. <Rectangle Fill="#FFFFFFFF" Stroke="DarkGray" RadiusX="5" RadiusY="5" Canvas.Left="10" Canvas.Top="10" Width="410" Height="90" />
  17. <StackPanel Orientation="Vertical" Canvas.Top="5" Canvas.Left="20">
  18. <esriWidgets:Toolbar x:Name="ToolBar1" MaxItemHeight="80" MaxItemWidth="80" Width="380" Height="80"
  19. ToolbarIndexChanged="ToolBar1_ToolbarIndexChanged"
  20. ToolbarItemClicked="ToolBar1_ToolbarItemClicked">
  21. <esriWidgets:Toolbar.Items>
  22. <esriWidgets:ToolbarItemCollection>
  23. <esriWidgets:ToolbarItem Text="添加点">
  24. <esriWidgets:ToolbarItem.Content>
  25. <Image Source="imgs/DrawPoint.png" Stretch="UniformToFill" Margin="5" />
  26. </esriWidgets:ToolbarItem.Content>
  27. </esriWidgets:ToolbarItem>
  28. <esriWidgets:ToolbarItem Text="添加折线">
  29. <esriWidgets:ToolbarItem.Content>
  30. <Image Source="imgs/DrawPolyline.png" Stretch="UniformToFill" Margin="5" />
  31. </esriWidgets:ToolbarItem.Content>
  32. </esriWidgets:ToolbarItem>
  33. <esriWidgets:ToolbarItem Text="添加多边形">
  34. <esriWidgets:ToolbarItem.Content>
  35. <Image Source="imgs/DrawPolygon.png" Stretch="UniformToFill" Margin="5" />
  36. </esriWidgets:ToolbarItem.Content>
  37. </esriWidgets:ToolbarItem>
  38. <esriWidgets:ToolbarItem Text="添加矩形">
  39. <esriWidgets:ToolbarItem.Content>
  40. <Image Source="imgs/DrawRectangle.png" Stretch="UniformToFill" Margin="5" />
  41. </esriWidgets:ToolbarItem.Content>
  42. </esriWidgets:ToolbarItem>
  43. <esriWidgets:ToolbarItem Text="添加曲线">
  44. <esriWidgets:ToolbarItem.Content>
  45. <Image Source="imgs/DrawFreehand.png" Stretch="UniformToFill" Margin="5" />
  46. </esriWidgets:ToolbarItem.Content>
  47. </esriWidgets:ToolbarItem>
  48. <esriWidgets:ToolbarItem Text="中止添加动做">
  49. <esriWidgets:ToolbarItem.Content>
  50. <Image Source="imgs/StopDraw.png" Stretch="UniformToFill" Margin="5" />
  51. </esriWidgets:ToolbarItem.Content>
  52. </esriWidgets:ToolbarItem>
  53. <esriWidgets:ToolbarItem Text="清空绘制的图形">
  54. <esriWidgets:ToolbarItem.Content>
  55. <Image Source="imgs/eraser.png" Stretch="UniformToFill" Margin="5" />
  56. </esriWidgets:ToolbarItem.Content>
  57. </esriWidgets:ToolbarItem>
  58. </esriWidgets:ToolbarItemCollection>
  59. </esriWidgets:Toolbar.Items>
  60. </esriWidgets:Toolbar>
  61. <TextBlock x:Name="StatusTextBlock" Text="" FontWeight="Bold" HorizontalAlignment="Center"/>
  62. </StackPanel>
  63. </Canvas>
复制代码
  1. private void Draw1_Loaded(object sender, RoutedEventArgs e)
  2. {
  3. Draw1.Map = Map1;
  4. }
  5. private void Draw1_OnDrawComplete(object sender, ESRI.ArcGIS.DrawEventArgs args)
  6. {
  7. ESRI.ArcGIS.GraphicsLayer graphicsLayer = Map1.Layers["GLayer2"] as ESRI.ArcGIS.GraphicsLayer;
  8. ESRI.ArcGIS.Graphic graphic = new ESRI.ArcGIS.Graphic()
  9. {
  10. Geometry = args.Geometry,
  11. Symbol = _activeSymbol,
  12. };
  13. graphicsLayer.Graphics.Add(graphic);
  14. }
  15. private void ToolBar1_ToolbarIndexChanged(object sender, ESRI.ArcGIS.Widgets.SelectedToolbarItemArgs e)
  16. {
  17. StatusTextBlock.Text = e.Item.Text;
  18. }
  19. private void ToolBar1_ToolbarItemClicked(object sender, ESRI.ArcGIS.Widgets.SelectedToolbarItemArgs e)
  20. {
  21. Draw1.Deactivate();
  22. switch (e.Index)
  23. {
  24. case 0: // Point
  25. Draw1.Activate(ESRI.ArcGIS.DrawMode.Point);
  26. _activeSymbol = strobeSymbol;
  27. break;
  28. case 1: // Polyline
  29. Draw1.Activate(ESRI.ArcGIS.DrawMode.Polyline);
  30. _activeSymbol = DefaultLineSymbol;
  31. break;
  32. case 2: // Polygon
  33. Draw1.Activate(ESRI.ArcGIS.DrawMode.Polygon);
  34. _activeSymbol = DefaultPolygonSymbol;
  35. break;
  36. case 3: // Rectangle
  37. Draw1.Activate(ESRI.ArcGIS.DrawMode.Rectangle);
  38. _activeSymbol = DefaultFillSymbol;
  39. break;
  40. case 4: // Freehand
  41. Draw1.Activate(ESRI.ArcGIS.DrawMode.Freehand);
  42. _activeSymbol = waveLineSymbol;
  43. break;
  44. case 5: // Stop Graphics
  45. break;
  46. case 6: // Clear Graphics
  47. ESRI.ArcGIS.GraphicsLayer graphicsLayer = Map1.Layers["GLayer2"] as ESRI.ArcGIS.GraphicsLayer;
  48. graphicsLayer.ClearGraphics();
  49. break;
  50. }
  51. }
复制代码
你们能够注意一下例子中添加的点符号和曲线符号。只要有足够的想象力,彻底能够利用Silverlight定制出很是炫的符号效果来。
原文地址: http://bbs.esrichina-bj.cn/ESRI/thread-44892-1-1.html
 

ArcGIS API for Silverlight开发入门(5):任务外包——Tasks

 经过上一节的学习,咱们已经知道了如何与GraphicLayer交互,但毕竟GIS不是一个画板,因此这节来看一下如何经过Silverlight API完成GIS中的分析功能。
        GIS之因此是一个通用的工具,就是由于它具备各类各样分析和处理数据的能力。Silverlight API中提供了Task,使咱们可以轻松完成常见的分析任务。
        先来考虑一下吃饺子的场景。要想吃饺子,咱们须要先去买菜,买肉,回家后在厨房里洗菜,揉面, 拌馅,包饺子,煮饺子,吃饺子,以后别忘了洗碗;另外一种状况就是去饭馆,告诉服务员我要吃3两茴香,3两韭菜的饺子,而后等着饺子端到你面前,开吃,走人。
        在ArcGISServer程序开发中,要完成GIS的分析功能其实和吃饺子是同样的。用ADF编程就像在家里吃饺子,除了架设服务器,全部的工做 基本上也都得咱们本身在服务器端来完成,要处理的地方比较多;而用客户端API编程至关于去外面吃饺子,咱们只要把任务交给相应的Task,以后接受结果 就好了,不用作饺子。惟一不一样的就是在外面吃完饺子别忘了付钱,而用Task完成分析任务则是免费的。这点也体如今使用客户端API中的Task时,是由 ArcGISOnline提供给你的,不须要本身购买AGS软件。
        如今来看看Silverlight API目前给咱们提供了那些Task功能:
Query:可以在已经发布的服务数据中,经过属性条件(能够属性字段中进行关系判断,字符查找等),图形条件(与输入的图形相交、包含、相离等),或者是二者的组合,查询出知足条件的数据并返回。至关于Engine中的SpatialFilter,固然也是QueryFilter。
Find:在地图数据的属性字段中查找包含有关键字参数的数据并返回。
Identity:对鼠标当前点击位置上的数据进行辨识并返回结果,能够对多个图层的数据进行辨识。
Address Locator:输入经纬度,返回地址结果(Geocoding);输入一个地方的地址,返回经纬度结果(Reverse Geocoding)。因为国内地图数据保密工做作的至关好,这个Task暂时用不到。
Geometry Service:能够对输入的地理数据进行如缓冲区,动态投影,面积/周长量算等几何操做。
Geoprocessing:可以完成复杂的GIS任务,相似ToolBox中的工具。
        抽象一下,能够看出,Query彻底能够完成Identity和Find的工做,但后二者在特定场合下使用起来比Query要方便的 多;Geoprocessing彻底能够替代Geometry Service,可是在利用REST API编写的程序中,要尽可能使用GeometryService。
        再抽象一下,Silverlight API中的这几个Task和JavaScript/FlexAPI中的Task是大同小异的,由于其实它们都是AGS 9.3 REST API中暴露出来的操做资源(OperationResource)见下图:

res-ops.jpg


 


        后面的代码中实际上也是把输入参数封装起来提交到了REST API的特定Endpoint上。要理解好客户端API中的Task,建议熟读AGS的 REST SDK
        Task的用法基本上相同,都遵循这几个步骤:初始化Task,设置Task所需参数,提交任务,等待服务器完成任务后,处理返回的结果;进饭馆,想好你要吃什么饺子,告诉服务员,等饺子作好端上来,开始吃。好了,下面咱们就经过一个实例( 点击这里,查看实例),来学习一下Query和Geometry两个Task的用法。

05_results.jpg


 



        首先选择工具条中的画线工具,在屏幕上画一条曲线,会根据曲线自动生成一个距离100千米的缓冲区显示在地图上,以后开始查询缓冲区图形通过的州 (相交),将结果显示在地图上。能够单击每一个州查看详细信息。这里假设你已学习了前几节的内容,只讨论Task用法的部分。
一、利用所画的线生成缓冲区。画线利用的是Draw工具中的Freehand,在这个动做完成后会触发Draw的OnDrawCompleted事件,天然能够在这里开始进行缓冲区的工做,用的是Geometry Service里的Buffer。
        初始化Geometry Service。假设已经在Map1中添加了ID为glayerResult的GraphicsLayer,linesymbolred是提早设置好的CartographicLineSymbol:
  1. private void Draw1_OnDrawComplete(object sender, DrawEventArgs args)
  2. {
  3. Draw1.Deactivate();//Freehand动做失效
  4. //将Freehand画的曲线显示在地图上
  5. GraphicsLayer glayer = Map1.Layers["glayerResult"] as GraphicsLayer;
  6. Graphic g = new Graphic();
  7. g.Symbol = linesymbolred;
  8. g.Geometry = args.Geometry;
  9. glayer.Graphics.Add(g);
  10. //初始化Geometry Service
  11. GeometryService geometrytask = new GeometryService("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Geometry/GeometryServer");
  12. }
复制代码
GeometryService 的初始化使用构造函数来完成的,里面接受一个URL,这个是Geometry Service的REST APIEndpoint。顺便说一下,不一样于其余服务好比MapService,一个GISServer只能发布一个GeometryService,并 且它的名称必须是Geometry。
        当一个Task完成时会触发Completed事件,失败时也有Failed事件,对这两个事件进行监听:
  1. geometrytask.BufferCompleted += new EventHandler(geometrytask_BufferCompleted);
  2. geometrytask.Failed += new EventHandler(geometrytask_Failed);
复制代码
设置Buffer操做所需的参数:
  1. BufferParameters bufferparameters = new BufferParameters();
  2. bufferparameters.Unit = LinearUnit.Kilometer;
  3. //必须指定下面两个spatialreference,不然buffer结果集为空
  4. bufferparameters.BufferSpatialReference = new SpatialReference(3395);
  5. bufferparameters.OutSpatialReference = Map1.SpatialReference;
  6. bufferparameters.Distances.Add(100);
  7. bufferparameters.Features.Add(g);
复制代码
BufferParameters 是专门用于Buffer的参数;BufferSpatialReference是将要Buffer的图形从新投影到这个坐标系下(经常须要根据地图数据所 在地方的状况来设置这个参数),并设置Buffer距离的单位为千米,Buffer的输出通常与地图坐标系一致;Buffer参数有一个Features 属性,是List类型,里面的Graphic都将被Buffer。下来将Buffer的任务提交到服务器(能够看出为何这些动做要叫Task):
  1. geometrytask.BufferAsync(bufferparameters);
复制代码
以 上代码都放在Draw1_OnDrawComplete函数中。任务提交到服务器后,由GeometryService接管,计算,完成后会马上将结果返 回给咱们,通知咱们结果已经完成的方式就是前面绑定的Completed事件。接收到结果后,首先将缓冲区显示出来:
  1. private void geometrytask_BufferCompleted(object sender, GraphicsEventArgs args)
  2. {
  3. if (args.Results.Count>0)
  4. {
  5. GraphicsLayer glayer = Map1.Layers["glayerResult"] as GraphicsLayer;
  6. Graphic g = new Graphic();
  7. g.Symbol = fillsymbolBuffer;
  8. g.Geometry = args.Results[0].Geometry;
  9. glayer.Graphics.Add(g);
  10. }
  11. }
复制代码
如图:

05_buffer.jpg


 


二、利用生成缓冲区的缓冲区进行空间查询。要达到咱们的目的,就还须要进行一个Query的Task,那么就能够在这里快马加鞭的开始Query的Task。步骤基本都是同样的,初始化,设置参数,提交结果,处理结果:
  1. private void geometrytask_BufferCompleted(object sender, GraphicsEventArgs args)
  2. {
  3. if (args.Results.Count>0)
  4. {
  5. GraphicsLayer glayer = Map1.Layers["glayerResult"] as GraphicsLayer;
  6. Graphic g = new Graphic();
  7. g.Symbol = fillsymbolBuffer;
  8. g.Geometry = args.Results[0].Geometry;
  9. glayer.Graphics.Add(g);
  10. //初始化QueryTask
  11. QueryTask querytask = new QueryTask("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Census_USA/MapServer/5");
  12. //准备接收结果或者处理失败的通知
  13. querytask.ExecuteCompleted += new EventHandler(querytask_ExecuteCompleted);
  14. querytask.Failed += new EventHandler(querytask_Failed);
  15. //设置Query Task所需的参数
  16. Query query = new Query();
  17. query.OutFields.Add("*");//也顺便设置了query.ReturnGeometry=true;
  18. query.Geometry = g.Geometry;
  19. query.SpatialRelationship = SpatialRelationship.esriSpatialRelIntersects;
  20. //向服务器上的对应图层提交任务
  21. querytask.ExecuteAsync(query);
  22. Map1.Cursor = System.Windows.Input.Cursors.Wait;
  23. }
  24. }
复制代码
这 里的查询实在美国州的图层上进行的,详细信息将QueryTask构造函数里的那个参数输入浏览器查看;query.Geometry是设置须要进行空间 查询的图形,就是上面缓冲区的结果;OutFields是查询结果须要返回的字段,这里返回所有字段,若是返回所有字段,则强制设置了 ReturnGeometry为true,若是咱们不须要处理结果的图形信息,则能够将这个参数设为false,以节省流量,显然这里不是;空间关系能够 参考API,与Engine中的彻底一致。
        接下来处理QueryTask完成后的结果:
  1. private void querytask_ExecuteCompleted(object sender, QueryEventArgs args)
  2. {
  3. GraphicsLayer graphicslayer = Map1.Layers["glayerResult"] as GraphicsLayer;
  4. FeatureSet featureset = args.FeatureSet;
  5. if (featureset != null && featureset.Features.Count > 0)
  6. {
  7. graphicslayer.ClearGraphics();
  8. listboxResults.Items.Clear();
  9. foreach (Graphic graphic in featureset.Features)
  10. {
  11. graphic.Symbol = fillsymbolresult;
  12. graphicslayer.Graphics.Add(graphic);
  13. }
  14. }
  15. MyMapTip.GraphicsLayer = graphicslayer;
  16. Map1.Cursor = System.Windows.Input.Cursors.Arrow;
  17. }
复制代码
上 面处理空间查询的结果只是将图形显示了出来,那么对于单击某个州后,显示出其详细信息该怎么办呢?从图一能够看出,用到了Silverlight的 DataGrid控件,信息从哪里去呢?记得上面咱们设置结果中返回的所有属性字段吗?它们存储在每一个Graphic的Attributes属性中。要么 绑定到DataGrid里,要么一条条添加……你可能已经发现了这条语句MyMapTip.GraphicsLayer =graphicslayer;,还记得第三节的Widgets吗?那里咱们落下了MapTip这个小家伙,如今派上用场了。除了在这里设置MapTip 的GraphicsLayer属性外,在xaml中有以下的定义:
  1. <esriWidgets:MapTip x:Name="MyMapTip" BorderBrush="#99000000"
  2. BorderThickness="1" Title="详细信息" VerticalOffset="10"
  3. HorizontalOffset="10" Background="#DDFFFFFF" />
复制代码
仅此而已。MapTip会自动找寻本身GraphicsLayer中的Graphic,当鼠标悬停在某个Grpahic上时,会自动读取它的Attributes属性并显示,小玩具又发挥了大做用。
        别忘了万一处理任务失败时的提示:
  1. private void geometrytask_Failed(object sender, TaskFailedEventArgs args)
  2. {
  3. MessageBox.Show("Buffer Error:" + args.Error);
  4. }
  5. private void querytask_Failed(object sender, TaskFailedEventArgs args)
  6. {
  7. MessageBox.Show("Query failed: " + args.Error);
  8. Map1.Cursor = System.Windows.Input.Cursors.Arrow;
  9. GraphicsLayer graphicslayer = Map1.Layers["glayerResult"] as GraphicsLayer;
  10. graphicslayer.ClearGraphics();
  11. }
复制代码
本节内容完毕。上面讲的相对简略,要理解各个Task和参数的用法,仍是须要熟悉 Silverlight API和 前面提到的REST API。另外,Geoprocessing Service其实是最强大Task,若是有本身的GISServer,彻底能够在上面发布自制的Model或者Python脚本,以完成各类GIS分 析任务,简单的在线编辑也是可能的。它的用法也万变不离其宗:初始化,设置参数,提交任务,处理结果。不一样的是GeoprocessingService 有两种提交任务的方法:同步和异步。前者服务器端处理完任务后会当即将结果发送回客户端;后者将任务提交后会获得服务器端返回的一个JobID,即便任务 处理完成也不会当即返回,而是须要你拿这个JobID去询问服务器:完成了吗?完成了吗?完成了吗?若是完成,则能够取回相应的结果。
        前面说到,虽然去外面吃饺子很方便,可是毕竟那是人家作好的,对于老饕来讲还须要本身的口感,本身下厨毕竟能控制整个过程的方方面面,哪怕你想作出 饺立方也都是有可能的。一样,ADF编程能够调用服务器端的ArcObjects,让你随心所欲,这点是客户端API不管如何也办不到的。
原文地址: http://bbs.esrichina-bj.cn/ESRI/thread-45302-1-1.html

ArcGIS API for Silverlight开发入门(6):图层类型小结

  在用SilverlightAPI开发的过程当中,不管是从客户端提交到服务器端的数 据,仍是从服务器端返回客户端的数据,都要表如今浏览器中,具体的来讲是Map控件里。但根据各自类型的不一样,好比数据源,地图服务的类型,是否缓存等, 决定了它们将处于某个图层里,前面讲过的GraphicsLayer就是一种图层。清楚地认识这些图层类型,对于处理于服务器与客户端之间的地图数据来讲 是很重要的。
        全部的图层都是从Layer类型继承而来的,能够参考下载的API中的对象模型图。
Layer
  |--TiledMapServiceLayer
  |       |--ArcGISTiledMapServiceLayer
  |--DynamicLayer
  |       |--DynamicMapServiceLayer
  |                 |--ArcGISDynamicMapServiceLayer
  |                 |--ArcGISImageServiceLayer
  |                 |--GPResultImageLayer
  |--GraphicsLayer
  |       |--FeatureLayer
  |--ElementLayer
        下面就按顺序认识一下这些图层吧,也包括Silverlight API中独有的FeatureLayer。

一、Layer:
        继承自Silverlight中的DependencyObject,并实现了INotifyPropertyChanged接口,是Silverlight API中其余图层的基类。能够把它当作麦子,再好吃的凉皮,泡馍都是由它作出来的;

二、TiledMapServiceLayer:
        继承自Layer,是全部使用了缓存的地图服务的基类。经过它能够在程序中加入通过缓存的,来自不一样数据源的地图服务。好比ArcGIS Server的地图服务,Google Map的地图,Virtual Earth的地图等;

三、ArcGISTiledMapServiceLayer:
        继承自TiledMapServiceLayer。像上面说的同样,这个图层扩展了TiledMapServiceLayer,因而支持由 ArcGISServer 9.3版本发布的通过缓存的地图服务;又好比ArcGIS Server9.2版本发布的缓存地图服务不支持REST方式链接,若是要在93的客户端API中使用的话,就能够经过 TiledMapServiceLayer扩展一个好比ArcGISTiledMapServiceLayer92,来支持92Server发布的缓存地 图服务;

四、DynamicLayer:
        继承自Layer,是动态地图服务的基类;

五、DynamicMapServiceLayer:
        继承自DynamicLayer,对应于TiledMapServiceLayer,要使用未通过缓存的动态地图服务,就得经过扩展这个图层来实现;

六、ArcGISDynamicMapServiceLayer:
        继承自DynamicMapServiceLayer,针对ArcGIS Server9.3版本发布的动态地图服务。同理,若是要在客户端API中使用其余动态地图服务,好比OGC的WMS服务,则也须要像这个图层同样,扩展 上面的DynamicMapServiceLayer来实现;

七、ArcGISImageServiceLayer:
        继承自DynamicMapServiceLayer,针对ArcGIS Server 9.3版本发布的ImageService,由于影像服务也属于动态的地图服务。在客户端API中,能够经过 ArcGISImageServiceLayer的一些属性,方便经过浏览器来展现服务器端的影像数据,好比经过BandIds属性,能够快速调整影像数 据显示波段的组合(RGB通道),提供不一样结果供用户查看。 点击这里,查看一个实例;

八、GPResultImageLayer:
        继承自DynamicMapServiceLayer,针对Geoprocessing服务所产生的结果。能够请求服务器端的GP服务将结果动态生成一张图片,将此图片做为GPResultImageLayer图层直接添加到Map控件中;

九、GraphicsLayer:
        继承自Layer,是图形数据集中展示的地方,在第四讲中已经详细讨论过了;

十、FeatureLayer:
        继承自GraphicsLayer,这也是Silverlight API中的亮点之一,经过它能够完成一个比较炫的功能:

featurelayer.gif


 


        整个过程在xaml中就能够实现,只须要在Map的Layers中插入如下代码便可:
  1. <esri:ArcGISTiledMapServiceLayer ID="StreetMapLayer" Url="http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_StreetMap_World_2D/MapServer"/>
  2. <esri:FeatureLayer ID="featurelayer"
  3. Url="http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Specialty/ESRI_StatesCitiesRivers_USA/MapServer/0"
  4. Where="POP1990 > 75000" ClusterFeatures="True" FlareBackground="#99FF0000" FlareForeground="White" MaximumFlareCount="9"
  5. FeatureSymbol="{StaticResource markersymbol}">
  6. <esri:FeatureLayer.OutFields>
  7. <sys:String>CITY_NAME</sys:String>
  8. <sys:String>POP1990</sys:String>
  9. </esri:FeatureLayer.OutFields>
  10. <esri:FeatureLayer.MapTip>
  11. <Grid Background="LightYellow">
  12. <StackPanel Margin="5">
  13. <TextBlock Text="{Binding Converter={StaticResource MyDictionaryConverter},
  14. ConverterParameter=CITY_NAME, Mode=OneWay}" FontWeight="Bold" />
  15. <StackPanel Orientation="Horizontal">
  16. <TextBlock Text="Population (1990): " />
  17. <TextBlock Text="{Binding Converter={StaticResource MyDictionaryConverter},
  18. ConverterParameter=POP1990, Mode=OneWay}" />
  19. </StackPanel>
  20. </StackPanel>
  21. <Border BorderBrush="Black" BorderThickness="1" />
  22. </Grid>
  23. </esri:FeatureLayer.MapTip>
  24. </esri:FeatureLayer>
复制代码
可 以看出这个FeatureLayer实际上是将一个Query查询封装到了一个GraphicsLayer中。经过url指定查询的图层,where指定查 询条件(也能够输入geometry指定查询的图形),最关键的是ClusterFeatures="True",当一个范围内feature过多时,就 将他们“聚合”在一块儿,以一个更大的符号表示出来,进一步放大时才将它们单独显示出来,若是聚合的目标不超过MaximumFlareCount设置的数 目,那么就会出现那个flare动画。在MapTip(继承自GraphicsLayer)里面进行了简单的设置,一个背景为黄色的Grid里显示两行文 字,用一个DictionaryConverter类将返回的Graphic.Attributes集合中的两个字段转换成String类型显示出来。顺 便提一下,FeatureLayer也能够用于线或面层的查询,但若是继续使用ClusterFeatures的话就没什么意义了。虽然 FeatureLayer封装的比较死,只能有此一种效果,但它提供给咱们一种思路,能够结合SilverlightRIA的特性,充分发挥本身的想象力 作出更炫的效果来;可是,对于须要展示海量(成百上千个)点数据的图层来讲,ClusterFeatures是一个很是有用的特性,毕竟将这么多点同时呈 现出来性能仍是有问题的。若是不使用ClusterFeatures,看起来应该是这样的:

featurelayer1.jpg


 


        不用FeatureLayer行吗?
        说到FeatureLayer,还有两个Renderer不得不提一下:UniqueValueRenderer和 ClassBreakerRenderer。它们都是依托FeatureLayer的,用于单值专题图的渲染。具体的用法都比较简单,能够查看API中的 Concepts。但Samples中的ThematicRendering例子并无采用这两种Renderer,而是人为地为每一个Graphic设置 了不一样的Symbol。目前看来虽然这两个Renderer有点鸡肋,但毕竟是如今3种客户端API中提供的惟一现成的Renderer,能够猜测也许下 个版本的SilverlightAPI中会有更加成熟的专题图Renderer直接供咱们使用;

十一、ElementLayer:
        继承自Layer,它能够用来专门呈现Silverlight中原生的FrameworkElement,好比视频,音频等。虽然在 FillSymbol的Fill属性中也能利用Brush类来展示一段视频,但毕竟有些“小气”,在ElementLayer中能够大大方方的放置 Silverlight元素。你可能会问,在Map控件以外,Grid等布局元素中不是也能放置Silverlight的东西吗,为何要放在 ElementLayer里呢?其实有个问题常常困扰GIS开发人员,就是想让一些非地理数据元素随着地图范围的变化(放大,缩小,平移)而变化,而无须 本身在Extent变化后从新计算客户端坐标,手工改变这些元素的位置。瞧,ElementLayer正解决了这个问题。

        目前Beta版的API中暂时有这么多图层类型,之后也许会继续增长。但万变不离其宗,无非就是从那几个基类中派生出来的。因此,下一节咱们就经过 一个实例来看看如何扩展基类的MapServiceLayer,来达到使用非ArcGIS Server数据源的目的。程序员

原文地址:http://bbs.esrichina-bj.cn/ESRI/thread-45537-1-1.htmlweb

ArcGIS API for Silverlight开发入门(7):使用非AGS数据源的图层

 经过上一节学习,能够看出在Silverlight API中不只能够轻松使用ArcGIS Server9.3发布的地图服务,也能够经过继承相应的图层,引入其余的数据源,好比ArcGIS Server9.2发布的地图服务,WMS服务,或者其余免费的数据。本节就经过一个实例,来看看如何将Google Map做为底图数据。
        Google Map是通过缓存的数据,因此须要继承的是TiledMapServiceLayer。那么在扩展这个图层的时候须要作哪些工做呢?首先就要明白 地图缓存的原理。能够看出咱们继承的这个图层,须要收集到如下几个信息:
一、Tiling Scheme Origin;
二、切图的范围,也就是FullExtent;
三、SpatialReference;
四、TileInfo,包括切图的大小,级数,以及每级的Resolution;
五、最后就是重写GetTileUrl方法。
        这是为何呢?能够想象,当地图控件的范围改变时,可以获取到当前范围的信息,那么只要把左上角和右下角之间的Tile所有按顺序显示出来就好了。 由前面的文章能够看出,当图层获取了一、二、三、4四个信息后,图层彻底能够自动计算出所需的Tile,最后根据GetTileUrl方法取回这些 Tile显示出来便可。
        那么对于Google Map的前4个参数,如何取得呢?记得在Catalog中作缓存时,有一个LoadTiling Scheme from Google Map吗?按照这个TilingScheme将一个地图服务作缓存,而后查看它的conf.xml和ServiceDirectory,便彻底能够取得这 几个参数了。另外关于如何获取Google Map的缓存,网上已经有很是多方法,这里就再也不讨论了。

googlemap.jpg


 



googlemap1.jpg


 


        代码以下:
  1. public class GoogleMap:TiledMapServiceLayer
  2.     {
  3.         public override void Initialize()
  4.         {
  5. this.FullExtent = new
  6. ESRI.ArcGIS.Geometry.Envelope(-20037508.342787,-20037508.342787,20037508.342787,20037508.342787);//(-180,
  7. -85.0511287798066,180, 85.0511287798066)
  8.             {
  9.                 SpatialReference = new ESRI.ArcGIS.Geometry.SpatialReference(102113);
  10.             };
  11.             this.SpatialReference = new ESRI.ArcGIS.Geometry.SpatialReference(102113);
  12.             //this.InitialExtent = this.FullExtent;
  13.             this.TileInfo = new TileInfo()
  14.             {
  15.                 Height = 256,
  16.                 Width = 256,
  17. Origin = new ESRI.ArcGIS.Geometry.MapPoint(-20037508.342787,
  18. 20037508.342787)//Origin = new ESRI.ArcGIS.Geometry.MapPoint(-180, 90)
  19.                 {
  20.                     SpatialReference = new ESRI.ArcGIS.Geometry.SpatialReference(102113)
  21.                 },
  22.                 Lods = new Lod[20]
  23.             };
  24.             double resolution = 156543.033928;
  25.             for (int i = 0; i < TileInfo.Lods.Length; i++)
  26.             {
  27.                 TileInfo.Lods[i] = new Lod() { Resolution = resolution };
  28.                 resolution /= 2;
  29.             }
  30.             base.Initialize();
  31.         }
  32.         public override string GetTileUrl(int level, int row, int col)
  33.         {
  34.             //google maps map
  35.             //string baseUrl = "http://mt0.google.com/mt/v=ap.92&hl=zh-CN&x=";
  36.             //string url = baseUrl + col.ToString() + "&y=" + row.ToString() + "&z=" + level.ToString() + "&s=";
  37.             //return url;
  38.             
  39.             ////google maps satallite
  40.             string baseUrl = "http://khm2.google.com/kh/v=38&hl=zh-CN&x=";
  41.             string url = baseUrl + col.ToString() + "&y=" + row.ToString() + "&z=" + level.ToString() + "&s=";
  42.             return url;
  43.         }
  44.     }
复制代码

须要注意一点,Google Map采用的是WGS 1984 Web Mercator投影,这个投影的wkid在RESTAPI中查不到,但在ServiceDirecotry中能够找到,是102113。另外,重写 DynamicMapServiceLayer也是基本相同的。
        以后也能够按照这个Tiling Scheme对本身的服务做缓存,本身的数据和Google Map即可以叠加在一块儿了。可是这样子使用GoogleMap的数据不只担忧会被封IP,并且更重要的是版权问题,毕竟不像JS API(有ArcGIS JavaScript Extension forthe Google Maps API )或者Flex API(有Google Map API forFlex)。别忘了MS有本身的Virtual Earth,下一节中就来看看如何在咱们的程序中名正言顺的使用VE的数据吧。编程

原文地址:http://bbs.esrichina-bj.cn/ESRI/thread-45582-1-1.htmlwindows

  SilverlightAPI中还包括了一个ESRI.ArcGIS.VirtualEarth.dll类库,让咱们能够方便的访问到老东家的 VirtualEarth服务。目前SilverlightAPI中提供的VirtualEarth服务有三种:Map,Geocode和 Routing,不过一看就知道后两种服务对于国内的数据来讲又无缘了。
        直接看如何使用它的Map服务获取地图数据吧。同前,新建一个Silverlight工程,添加ESRI.ArcGIS.dll和ESRI.ArcGIS.VirtualEarth.dll的引用,引入xml命名空间,在xaml里面这样写:
  1. <esri:Map x:Name="Map1" Loaded="Map1_Loaded">
  2.             <esri:Map.Layers>
  3.                 <esriVE:TileLayer ID="VELayer" LayerStyle="AerialWithLabels" ServerType="Staging"/>
  4.             </esri:Map.Layers>
  5.         </esri:Map>
复制代码
可 以看出,和添加其余图层基本是同样的。SIlverlightAPI中针对VE地图的图层类型是TileLayer,LayerStyle有三 种:Road,Aerial和AerialWithLabels,分别对应矢量图,影像图和带街道标注的影像图。ServerType就比较特殊了,有两 种:Staging和Production,分别对应访问VE服务的帐户类别,前者是免费的,后者是收费的。若是你此时运行程序的话,那是看不到地图的, 由于TileLayer还有个关键的token属性没有设置。
        VE的服务那是至关安全,每次访问VE的服务,都要提供一个token(一个加密字符串)来进行身份验证,而这个token又是根据 TokenService自动生成的,要经过TokenService生成一个token,又须要一个合法的Microsoft Virtual Earth Platformdeveloper account……明白了这个过程,就来作咱们的工做吧。
        首先, 去申请一个Microsoft Virtual Earth Platform developer account,固然以前你还得有一个Windows Live帐号。申请的这个帐号是Evaluation版的,因此决定了之后咱们只能使用Staging的服务,若是要把它变成Production版本,能够经过邮件联系微软,而后缴费;
        以后到注册时所填的邮箱去激活申请的Microsoft Virtual Earth Platform developeraccount帐号,而后为其设置密码(必须是8-14为之间,包括大、小写字母,数字,且还要有非字母数字的字符,和windows server2008是同样的),咱们日常确定不会这样设置密码,为了以防万一,建议赶忙把设置好的密码记录下来,
没准哪天就忘了。如今就能够用这个帐户和密码来访问TokenService,经过它生成token,交给TileLayer的token属性。
        为了安全目的考虑,token是不建议也不能直接在Silverlight程序中进行设置的。那么怎么办呢?这样办:一、经过装载 Silverlight的aspx页面的Page_Load方法,来申请咱们的token,并把它添加到Silverlight的初始参数中,二、而后当 Silverlight插件载入的时候,把token读出来,三、在Map_Loaded事件中,赋给TileLayer。
一、经过TokenService申请token:
在webapp中add webreference,url用 https://staging.common.virtualearth.net/find-30/common.asmx?wsdl,起个名字叫VirtualEarthService.TokenService。
  1. <script language="C#" runat="Server">
  2.     private string VEAccountID = "你的ID(注意只是AccountID)";
  3.     private string VEAccountPassword="你的密码";
  4.    
  5.     protected void Page_Load(object sender,EventArgs e)
  6.     {
  7. _08_virtual_earth.Web.VirtualEarthService.TokenService.CommonService
  8. commenservice = new
  9. _08_virtual_earth.Web.VirtualEarthService.TokenService.CommonService();
  10.         
  11.         commenservice.Credentials = new System.Net.NetworkCredential(VEAccountID, VEAccountPassword);
  12. _08_virtual_earth.Web.VirtualEarthService.TokenService.TokenSpecification
  13. tokenSpec=new
  14. _08_virtual_earth.Web.VirtualEarthService.TokenService.TokenSpecification();
  15.         tokenSpec.TokenValidityDurationMinutes=480;
  16.         if (HttpContext.Current!=null && !HttpContext.Current.Request.IsLocal)
  17.         {
  18.             tokenSpec.ClientIPAddress=HttpContext.Current.Request.UserHostAddress;
  19.         }
  20.         else
  21.         {
  22.             tokenSpec.ClientIPAddress="127.0.0.1";
  23.         }
  24.         
  25.         string token = "";
  26.         token = commenservice.GetClientToken(tokenSpec);
  27.         Xaml1.InitParameters = string.Format("token={0}", token);
  28.     }
  29. </script>
复制代码
其中Xaml1是Silverlight插件的ID:<asp:Silverlight ID="Xaml1" runat="server"...
二、Silverlight插件载入时读出这个token。在App.xaml.cs中:
  1. private void Application_Startup(object sender, StartupEventArgs e)
  2.         {
  3.             VEtoken = e.InitParams["token"];
  4.             this.RootVisual = new Page();
  5.         }
复制代码
三、最后在加载地图控件后,交付token:
  1. private void Map1_Loaded(object sender, RoutedEventArgs e)
  2.         {
  3.             foreach (Layer layer in Map1.Layers)
  4.                 if (layer is TileLayer)
  5.                     (layer as TileLayer).Token = (Application.Current as App).VEtoken;
  6.         }
复制代码
终于能看见VE的图了。固然,咱们的开发帐户是免费的,因此地图上有不少“Staging”麻点(每一个tile一个):

08_ve.jpg


 



        至此,ArcGIS API for Silverlight的开发入门已经讲完了,我和你们同样也是边学边写的,恰好这两天SIlverlightAPI又升级了第二个Beta版。其实 Silverlight和Flex同样,能使传统的WebGIS散发出全新的魅力,从而使咱们的程序在RIA的道路上大踏步前进,可以作出什么样的效果也 基本只受想象力的制约了。随着Silverlight3的推出,咱们也有理由相信Silverlight的明天会更好。api

原文地址:http://bbs.esrichina-bj.cn/ESRI/thread-45835-1-1.html