Silverlight調用GP服務詳解
上一篇主要講了如何發布GP服來繪制等值線及等直面,這里主要將如何通過Silverlight來調用GP服務。
這里先寫一下具體的調用過程:
- 聲明GP服務變量(Geoprocessor),並實例化
- 注冊GP服務任務完成事件及失敗事件
- 根據發布的GP服務,定義GP服務的參數
- 輸入GP服務參數請求GP服務
- 獲取結果:在Compeleted事件函數中完成獲取結果的代碼,對於是要素類結果,需要注冊GetResultDataCompleted事件,對於是柵格數據結果需要注冊GetResultImageLayerCompleted事件,然后在事件的回調函數中完成最終結果的獲取。
這里需要注意的問題:
a. GP服務是同步調用還是異步調用
b. 獲得結果的坐標系是否和當前一致
c. GP服務的輸入參數必須和發布的GP服務一致(之后會詳細說明)
d. 獲取結果的名稱必須和發布的GP服務一致(之后會詳細講到)
以上大致的說了一下GP服務調用的基本過程,下面就開始正式的工作吧。
一.基本界面
首先我們構建一個簡單的Web界面,如下圖所示:
這里需要實現的基本功能是:可以保存每一次添加的Graphic(xml格式),並能夠再次讀取這些Graphic.根據加載的Graphic實現基本的預測,即調用GP服務。
說明:為了節省時間,這里我已將用到的點的數據保存成了一個xml文檔,所有需要的數據都從xml中讀取。
二.加載xml格式的Graphic信息
這里就是遍歷xml中所有Graphic節點,然后讀取相應的信息(節點的名稱根據我們保存xml時定義的不同而不同,后面會給出保存xml的代碼)。讀取xml信息的代碼如下:

1 //打開加載數據對話框 2 OpenFileDialog openFileDialog = new OpenFileDialog(); 3 //指定xml問價格式 4 openFileDialog.Filter = "XML Files(*.xml)|*.xml"; 5 if (openFileDialog.ShowDialog() == true) 6 { 7 using (Stream stream = openFileDialog.File.OpenRead()) 8 { 9 XDocument doc = XDocument.Load(stream); 10 //遍歷xml中的Graphic節點 11 foreach (XElement element in doc.Descendants("Graphic")) 12 { 13 //遍歷Graphic節點下的Location節點 14 foreach (XElement LocationElement in element.Descendants("Location")) 15 { 16 //獲得Location節點下的坐標 17 double LocationX = Convert.ToDouble(LocationElement.Element("LocationX").Value); 18 double LocationY = Convert.ToDouble(LocationElement.Element("LocationY").Value); 19 //獲得Graphic節點下的濃度值 20 double PollutionC = Convert.ToDouble(element.Element("PolutionC").Value); 21 //繪制Graphic 22 CreatGraphic(LocationX, LocationY, PollutionC); 23 } 24 } 25 } 26 }
CreatGraphic方法表示在地圖上根據獲得的坐標和濃度值繪制出一個點。

//定義一個圖層,所以的Graphic將在此圖層上繪制 private GraphicsLayer graphicsLayer = null; private void CreatGraphic(double locationx, double locationy, double pollutionc) { //構建一個Graphic,並定義其樣式 Graphic g = new Graphic() { Geometry = new MapPoint() { X=locationx, Y=locationy, SpatialReference=map.SpatialReference }, Symbol = new SimpleMarkerSymbol() { Size = 9, Color = new SolidColorBrush(Colors.Blue), Style = SimpleMarkerSymbol.SimpleMarkerStyle.Circle }, }; if (map.Layers["GraphicsPoints"] == null) { graphicsLayer = new GraphicsLayer() { ID = "GraphicsPoints" }; map.Layers.Add(graphicsLayer); } //添加濃度屬性 g.Attributes.Add("PolutionC", pollutionc); // graphicsLayer.Graphics.Add(g); }
三.保存xml格式的Graphic信息
這里我們將GraphicLayer上所有的點的信息保存成xml格式。需要注意的是,xml中節點名稱必須和讀取xml文件時使用的節點名保持一致。否則之后我們無法讀取我們保存的信息。具體代碼如下:

1 //若要素圖層不存在則返回 2 if (map.Layers["GraphicsPoints"] == null) 3 return; 4 //若圖層要素為空也返回 5 GraphicsLayer graphicslayer = map.Layers["GraphicsPoints"] as GraphicsLayer; 6 if (graphicslayer.Graphics.Count <= 0) 7 return; 8 //打開保存對話框 9 SaveFileDialog saveFileDialog = new SaveFileDialog(); 10 //指定xml文件格柵 11 saveFileDialog.DefaultExt = "xml"; 12 saveFileDialog.Filter = "XML Files (*.xml)|*.xml"; 13 //指定默認的文件名為當前的時間 14 saveFileDialog.DefaultFileName = string.Format("GraphicInfo{0}", GetCurrentDateTimeString()); 15 16 if (saveFileDialog.ShowDialog() == true) 17 { 18 using (Stream stream = saveFileDialog.OpenFile()) 19 { 20 StreamWriter streamWriter = new StreamWriter(stream, System.Text.Encoding.UTF8); 21 int GraphicNum = 1; 22 23 foreach (Graphic g in graphicslayer.Graphics) 24 { 25 //調用自定義GetGeneratedXML方法,構建xml 26 GetGeneratedXML(GraphicNum, g); 27 GraphicNum++; 28 } 29 streamWriter.Write(doc.ToString()); 30 streamWriter.Close(); 31 stream.Close(); 32 } 33 }
GetGeneratedXML方法代碼如下:

1 private void GetGeneratedXML(int graphicID, Graphic g) 2 { 3 MapPoint mapPoint = g.Geometry as MapPoint; 4 XElement graphic = new XElement("Graphic", new XAttribute("ID", graphicID), 5 new XElement("Location", 6 new XElement("LocationX", mapPoint.X), 7 new XElement("LocationY", mapPoint.Y)), 8 new XElement("PolutionC", Convert.ToDouble(g.Attributes["PolutionC"]))); 9 doc.Root.Add(graphic); 10 }
GetCurrentDateTimeString方法如下:

1 private string GetCurrentDateTimeString() 2 { 3 string TimeString; 4 DateTime CurrentTime = new DateTime(); 5 CurrentTime = System.DateTime.Now; 6 int year = CurrentTime.Year; 7 int month = CurrentTime.Month; 8 int day = CurrentTime.Day; 9 int hour = CurrentTime.Hour; 10 int minute = CurrentTime.Minute; 11 int second = CurrentTime.Second; 12 TimeString = string.Format("{0}{1}{2}{3}{4}{5}", year, month, day, hour, minute, second); 13 return TimeString; 14 }
四.根據添加的點,進行預測及可視化表達(繪制等值線及等值面)
到這里為止,才算是真正開始我們的GP服務。具體的調用過程在開始的時候作了一個大致的介紹,下面開始詳細的講解。
4.1 定義GP服務變量

1 //定義GP服務變量 2 private Geoprocessor InterpolationTask = null;//繪制等值面 3 private Geoprocessor ContourTask = null;//繪制等值線
並且實例化GP服務變量,並注冊相應的事件

1 //等值線GP服務 2 ContourTask = new Geoprocessor("http://qzj-pc/ArcGIS/rest/services/ContourService_with_Focal_Statistics/GPServer/ContourService"); 3 ContourTask.JobCompleted += new EventHandler<JobInfoEventArgs>(ContourTask_JobCompleted); 4 ContourTask.GetResultDataCompleted += new EventHandler<GPParameterEventArgs>(ContourTask_GetResultDataCompleted); 5 ContourTask.Failed += new EventHandler<TaskFailedEventArgs>(ContourTask_Failed); 6 //等值面GP服務 7 InterpolationTask = new Geoprocessor("http://qzj-pc/ArcGIS/rest/services/InterpolationService_Stretch/GPServer/InterpolationModel"); 8 InterpolationTask.JobCompleted += new EventHandler<JobInfoEventArgs>(InterpolationTask_JobCompleted); 9 InterpolationTask.GetResultImageLayerCompleted += new EventHandler<GetResultImageLayerEventArgs>(InterpolationTask_GetResultImageLayerCompleted); 10 InterpolationTask.Failed += new EventHandler<TaskFailedEventArgs>(InterpolationTask_Failed);
4.2 定義GP服務的請求參數
這里需要的參數必須和我們發布的GP服務一致。我們打開繪制等值線的GP服務鏈接,基本參數如下所示:
以上是繪制等值面的GP服務參數列表,並給出了參數信息的詳細說明,這里我們可以看出繪制等值面的GP服務只有一個輸入參數:PollutionPoints,類型是GPFeatureRecordSetLayer,也就是要素集。同時只有一個輸出參數:RasterData,類型是GPRasterDataLayer,即柵格數據。
下面我們定義繪制等值面的GP服務參數。
1 //添加這段代碼,非常有用,否則將無法獲取GP服務的結果 2 HttpWebRequest.RegisterPrefix("http://", System.Net.Browser.WebRequestCreator.ClientHttp); 3 //將從xml中解析出來的點構建成要素集,並作為我們GP服務輸入的參數 4 FeatureSet featureSet = new FeatureSet(graphicsLayer.Graphics); 5 //定義GP服務參數:InterpolationJobParameter 6 List<GPParameter>InterpolationJobParameter = new List<GPParameter>(); 7 //添加GP服務參數 8 InterpolationJobParameter.Add(new GPFeatureRecordSetLayer("PollutionPoints", featureSet)); 9 //請求等直面GP服務 10 InterpolationTask.SubmitJobAsync(InterpolationJobParameter);
注意這里的PollutionPoints,這里的名稱必須和之前我們發布的GP服務參數列表一致。而且還需要注意這里的GP服務參數類型,必須是要素集。
同理,我們可以看看繪制等值線的GP服務參數列表,如下圖所示:
后台定義的繪制等值線的GP服務參數代碼:
1 //定義繪制等值線的GP服務參數 2 List<GPParameter> ContourJobParameter = new List<GPParameter>(); 3 //添加要素集參數 4 ContourJobParameter.Add(new GPFeatureRecordSetLayer("PollutionPoints", featureSet)); 5 //添加等值線間距參數 6 ContourJobParameter.Add(new GPDouble("Contour_interval", 4.0001)); 7 //添加容差設置參數 8 ContourJobParameter.Add(new GPLinearUnit("XY_Tolerance", esriUnits.esriMeters, 1)); 9 //請求等值線GP服務 10 ContourTask.SubmitJobAsync(ContourJobParameter);
注意上面的GP服務參數名稱必須保持一致。
五.獲取GP服務的結果,並在地圖上顯示
之前說過,請求GP服務結果都會有一個Completed事件,所以我們獲取結果的代碼將在該事件回調函數中完成。之前我們已注冊了GP事件,其回調函數如下:
下面我們就開始獲取等值面的結果。
在請求等值面GP服務的完成事件中添加如下代碼:
1 private void InterpolationTask_JobCompleted(object sender, JobInfoEventArgs e) 2 { 3 4 if (e.JobInfo.JobStatus == esriJobStatus.esriJobFailed) 5 { 6 MessageBox.Show("請求服務失敗!" + e.JobInfo.Messages.ToString()); 7 return; 8 } 9 HttpWebRequest.RegisterPrefix("http://", System.Net.Browser.WebRequestCreator.ClientHttp); 10 //獲取GP服務結果,這里需要注意的是結果的名稱必須和我們發布的GP服務參數列表一致 11 InterpolationTask.GetResultImageLayerAsync(e.JobInfo.JobId, "RasterData"); 12 }
注意這里的RasterData必須和之前我們發布的GP服務輸出參數名稱一致,否則將無法獲取到結果。
這里我們注意到,GetResultImageLayerAsync也是一個異步請求,因此我們需要在其完成事件的回調函數中獲得最終的結果,之前我們已經注冊了其完成的事件函數,現在添加如下代碼:
1 private void InterpolationTask_GetResultImageLayerCompleted(object sender, GetResultImageLayerEventArgs e) 2 { 3 //返回的結果實際上是一張圖片 4 GPResultImageLayer imagelayer = e.GPResultImageLayer; 5 //定義圖層的ID 6 imagelayer.ID = "InterpolationLayer"; 7 //設置透明度 8 imagelayer.Opacity = 0.7; 9 //清空原有的結果 10 if (map.Layers["InterpolationLayer"] != null) 11 { 12 map.Layers.Remove(map.Layers["Interpolation"]); 13 } 14 //添加當前結果到圖層中 15 map.Layers.Add(imagelayer); 16 MessageBox.Show("繪制完成!"); 17 }
這里說明一點:由於柵格數據不支持在Web客戶端直接讀取,因此我們通過結果地圖服務,將其在服務器端根據我們設置的渲染格式,生成一張圖片。然后在客戶端實際上是獲取這張圖片,而不是柵格數據,當客戶端的地圖范圍發生改變時(移動,縮放),就會在服務器端動態的生成響應的圖片,並在Web客戶端顯示其相應的結果。
最后,你還可以在Failed事件中添加GP服務請求失敗時的相應處理。
private void InterpolationTask_Failed(object sender, TaskFailedEventArgs e) { MessageBox.Show("請求服務失敗:" + e.Error.ToString()); }
以上的過程便是獲取GP繪制等直面的結果。
下面是獲得的結果:
點擊加載xml文檔,打開xml文件,就會添加相應的Graphic,如下圖所示:
接着點擊預測,結果如下:
接下來,我們看看如何獲取等值線的結果。其過程和等值面的獲取相似,只不過等值線的結果是線要素,而等值面則是一張圖片,兩則在獲取和顯示上有一點點的差別。
下面是繪制等值線GP請求的Completed事件響應函數代碼,和等值面的差不多,唯一不同的就是異步請求的函數,以及闡述不一樣。
1 private void ContourTask_JobCompleted(object sender, JobInfoEventArgs e) 2 { 3 if (e.JobInfo.JobStatus == esriJobStatus.esriJobFailed) 4 { 5 MessageBox.Show("請求等值線服務失敗:" + e.JobInfo.Messages); 6 return; 7 } 8 HttpWebRequest.RegisterPrefix("http://", System.Net.Browser.WebRequestCreator.ClientHttp); 9 //請求繪制等值線GP服務,注意這里和等值面的異步請求函數不一樣 10 ContourTask.GetResultDataAsync(e.JobInfo.JobId, "ContourLine_shp"); 11 }
同樣需要注意請求結果的參數必須和發布的等值線GP服務輸出參數名稱一致。
然后我們在GetResultDataCompleted事件響應函數中添加相應的代碼獲取結果,並在地圖上顯示出來。代碼如下:
1 private void ContourTask_GetResultDataCompleted(object sender, GPParameterEventArgs e) 2 { 3 if (map.Layers["ContourLayer"] != null) 4 { 5 map.Layers.Remove(map.Layers["ContourLayer"]); 6 } 7 GraphicsLayer contourLayer = new GraphicsLayer() { 8 ID="ContourLayer" 9 }; 10 11 GPFeatureRecordSetLayer featureSetLayer = e.Parameter as GPFeatureRecordSetLayer; 12 //遍歷結果獲取其中包含的要素,並添加到等值線圖層中 13 foreach (Graphic graphic in featureSetLayer.FeatureSet.Features) 14 { 15 //設置等值線的樣式 16 graphic.Symbol = new SimpleLineSymbol() 17 { 18 Style = SimpleLineSymbol.LineStyle.Solid, 19 Color = new SolidColorBrush(Colors.Blue), 20 Width = 3 21 }; 22 contourLayer.Graphics.Add(graphic); 23 } 24 //將結果添加到當前的地圖中 25 map.Layers.Add(contourLayer); 26 MessageBox.Show("等值線繪制完成!"); 27 }
同理添加GP服務請求失敗處理函數:
private void ContourTask_Failed(object sender, TaskFailedEventArgs e) { MessageBox.Show("請求等值線服務失敗:" + e.Error.ToString()); }
這樣獲取等值線結果的工作已經完成,下面看一看效果:
到此,關於Silverlight調用GP服務繪制等值線以及等值面的所有過程已經講述完畢。
(版權所有,轉載請標明出處)