天天看點

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)見下圖:

ArcGIS API for Silverlight開發入門(5):任務外包——Tasks
ArcGIS API for Silverlight開發入門(5):任務外包——Tasks

2009-4-26 13:27

ArcGIS API for Silverlight開發入門(5):任務外包——Tasks
ArcGIS API for Silverlight開發入門(5):任務外包——Tasks

        首先選擇工具條中的畫線工具,在螢幕上畫一條曲線,會根據曲線自動生成一個距離100公裡的緩沖區顯示在地圖上,之後開始查詢緩沖區圖形經過的州(相交),将結果顯示在地圖上。可以單擊每個州檢視詳細資訊。這裡假設你已學習了前幾節的内容,隻讨論Task用法的部分。

1、利用所畫的線生成緩沖區。畫線利用的是Draw工具中的Freehand,在這個動作完成後會觸發Draw的OnDrawCompleted事件,自然可以在這裡開始進行緩沖區的工作,用的是Geometry Service裡的Buffer。

        初始化Geometry Service。假設已經在Map1中添加了ID為glayerResult的GraphicsLayer,linesymbolred是提前設定好的CartographicLineSymbol:

private void Draw1_OnDrawComplete(object sender, DrawEventArgs args)

{

Draw1.Deactivate();//Freehand動作失效

//将Freehand畫的曲線顯示在地圖上

GraphicsLayer glayer = Map1.Layers["glayerResult"] as GraphicsLayer;

Graphic g = new Graphic();

g.Symbol = linesymbolred;

g.Geometry = args.Geometry;

glayer.Graphics.Add(g);

//初始化Geometry Service

GeometryService geometrytask = new GeometryService("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Geometry/GeometryServer");

}

複制代碼

GeometryService的初始化使用構造函數來完成的,裡面接受一個URL,這個是Geometry Service的REST APIEndpoint。順便說一下,不同于其他服務比如MapService,一個GISServer隻能釋出一個GeometryService,并且它的名稱必須是Geometry。

        當一個Task完成時會觸發Completed事件,失敗時也有Failed事件,對這兩個事件進行監聽:

geometrytask.BufferCompleted += new EventHandler(geometrytask_BufferCompleted);

geometrytask.Failed += new EventHandler(geometrytask_Failed);

設定Buffer操作所需的參數:

BufferParameters bufferparameters = new BufferParameters();

bufferparameters.Unit = LinearUnit.Kilometer;

//必須指定下面兩個spatialreference,否則buffer結果集為空

bufferparameters.BufferSpatialReference = new SpatialReference(3395);

bufferparameters.OutSpatialReference = Map1.SpatialReference;

bufferparameters.Distances.Add(100);

bufferparameters.Features.Add(g);

BufferParameters是專門用于Buffer的參數;BufferSpatialReference是将要Buffer的圖形重新投影到這個坐标系下(常常需要根據地圖資料所在地方的情況來設定這個參數),并設定Buffer距離的機關為公裡,Buffer的輸出一般與地圖坐标系一緻;Buffer參數有一個Features屬性,是List類型,裡面的Graphic都将被Buffer。下來将Buffer的任務送出到伺服器(可以看出為什麼這些動作要叫Task):

geometrytask.BufferAsync(bufferparameters);

以上代碼都放在Draw1_OnDrawComplete函數中。任務送出到伺服器後,由GeometryService接管,計算,完成後會立刻将結果傳回給我們,通知我們結果已經完成的方式就是前面綁定的Completed事件。接收到結果後,首先将緩沖區顯示出來:

private void geometrytask_BufferCompleted(object sender, GraphicsEventArgs args)

if (args.Results.Count>0)

g.Symbol = fillsymbolBuffer;

g.Geometry = args.Results[0].Geometry;

如圖:

ArcGIS API for Silverlight開發入門(5):任務外包——Tasks
ArcGIS API for Silverlight開發入門(5):任務外包——Tasks

2、利用生成緩沖區的緩沖區進行空間查詢。要達到我們的目的,就還需要進行一個Query的Task,那麼就可以在這裡馬不停蹄的開始Query的Task。步驟基本都是一樣的,初始化,設定參數,送出結果,處理結果:

//初始化QueryTask

QueryTask querytask = new QueryTask("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Census_USA/MapServer/5");

//準備接收結果或者處理失敗的通知

querytask.ExecuteCompleted += new EventHandler(querytask_ExecuteCompleted);

querytask.Failed += new EventHandler(querytask_Failed);

//設定Query Task所需的參數

Query query = new Query();

query.OutFields.Add("*");//也順便設定了query.ReturnGeometry=true;

query.Geometry = g.Geometry;

query.SpatialRelationship = SpatialRelationship.esriSpatialRelIntersects;

//向伺服器上的對應圖層送出任務

querytask.ExecuteAsync(query);

Map1.Cursor = System.Windows.Input.Cursors.Wait;

這裡的查詢實在美國州的圖層上進行的,詳細資訊将QueryTask構造函數裡的那個參數輸入浏覽器檢視;query.Geometry是設定需要進行空間查詢的圖形,就是上面緩沖區的結果;OutFields是查詢結果需要傳回的字段,這裡傳回全部字段,如果傳回全部字段,則強制設定了ReturnGeometry為true,如果我們不需要處理結果的圖形資訊,則可以将這個參數設為false,以節省流量,顯然這裡不是;空間關系可以參考API,與Engine中的完全一緻。

        接下來處理QueryTask完成後的結果:

private void querytask_ExecuteCompleted(object sender, QueryEventArgs args)

GraphicsLayer graphicslayer = Map1.Layers["glayerResult"] as GraphicsLayer;

FeatureSet featureset = args.FeatureSet;

if (featureset != null && featureset.Features.Count > 0)

graphicslayer.ClearGraphics();

listboxResults.Items.Clear();

foreach (Graphic graphic in featureset.Features)

graphic.Symbol = fillsymbolresult;

graphicslayer.Graphics.Add(graphic);

MyMapTip.GraphicsLayer = graphicslayer;

Map1.Cursor = System.Windows.Input.Cursors.Arrow;

上面處理空間查詢的結果隻是将圖形顯示了出來,那麼對于單擊某個州後,顯示出其詳細資訊該怎麼辦呢?從圖一可以看出,用到了Silverlight的DataGrid控件,資訊從哪裡去呢?記得上面我們設定結果中傳回的全部屬性字段嗎?它們存儲在每個Graphic的Attributes屬性中。要麼綁定到DataGrid裡,要麼一條條添加……你可能已經發現了這條語句MyMapTip.GraphicsLayer =graphicslayer;,還記得第三節的Widgets嗎?那裡我們落下了MapTip這個小家夥,現在派上用場了。除了在這裡設定MapTip的GraphicsLayer屬性外,在xaml中有如下的定義:

<esriWidgets:MapTip x:Name="MyMapTip" BorderBrush="#99000000"

BorderThickness="1" Title="詳細資訊" VerticalOffset="10"

HorizontalOffset="10" Background="#DDFFFFFF" />

僅此而已。MapTip會自動找尋自己GraphicsLayer中的Graphic,當滑鼠懸停在某個Grpahic上時,會自動讀取它的Attributes屬性并顯示,小玩具又發揮了大作用。

        别忘了萬一處理任務失敗時的提示:

private void geometrytask_Failed(object sender, TaskFailedEventArgs args)

MessageBox.Show("Buffer Error:" + args.Error);

private void querytask_Failed(object sender, TaskFailedEventArgs args)

MessageBox.Show("Query failed: " + args.Error);

        前面說到,雖然去外面吃餃子很友善,但是畢竟那是人家做好的,對于老饕來說還需要自己的口感,自己下廚畢竟能控制整個過程的方方面面,哪怕你想做出餃立方也都是有可能的。同樣,ADF程式設計可以調用伺服器端的ArcObjects,讓你為所欲為,這點是用戶端API無論如何也辦不到的。

繼續閱讀