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

相關文章
相關標籤/搜索