ArcGIS.Server.9.2.DotNet在地图中显示xml数据(自带例子 九、一)
目的:
1.arcgis server9.2 ADF实现自定义数据源,在地图中显示自定义的xml数据。
准备工作:
1.用ArcGis Server Manager或者ArcCatalog发布一个叫usa的Map Service,并且把这个Service启动起来。
2.参考DeveloperKit\SamplesNET\Server\Web_Applications目录下的Common_CustomDataSourceCSharp.zip。
开始:
1.数据显示实现说明:Map控件->MapResourceManager控件->数据源,MapResourceManager控件选择不同的数据源(GISDataSource)加入应用成为Resource,这样Map控件可以通过Resource与数据源进行交互,一个GISDataSource可以有多个Resource,常用的是MapResource 和 GeocodeResource。一个Resource可以有多个Functionatily,通常分为common API和special API两种,data source 决定了resource能做什么(能实现哪些功能的接口或functionality)。这样通过上面的描述就很容易明白一个自定义的xml数据要在Map控件中显示必须先能加入到MapResourceManager控件中成为Resource。
2.在MapResourceManager的MapResourcesItem集合编辑器的Map Resource Definition Editor工具中ESRI已经内置了很多的DataSource类型,在Type选项中有GraphicsLayer、ArcGIS Server Local、OGC (WMS) Service、ArcIMS、ArcGIS Server Internet、ArcWeb Services这几种类型可以选择,现在要显示自定义的xml数据源,就需要为添加新的一个DataSource类型来实现。
3.在MapResourcesItem集合编辑器的Map Resource Definition Editor工具中DataSource类型,是通过一个config的配置文件来实现的,在ArcGIS.Server.9.2.DotNet中这些配置文件放置在ArcGisServer安装目录的DotNet文件内,这里能找到ArcGIS Server Local、GraphicsLayer、ArcIMS等所有DataSource类型的配置文件,可以用记事本打这些文件学习一下它是如何构成的。在这里DotNet文件内添加一个名为ESRI.ArcGIS.ADF.Web.DataSources.REXMLData.config的配置文件用来给我们的工程用,具体的内容和说明如下:
4.有了上面的大概的思路后就开始动手具体功能实现,新建名为CustomDataSource的ASP.NET Web应用程序,然后添加一个Default_REXMLData.aspx页面用来具体功能的展示。
5.在CustomDataSource的解决方案中在添加一个名为REXMLDataSource的类库工程,用来实现自定义DataSource类型和MapResource的功能。同时在CustomDataSource的ASP.NET Web应用程序中添加对这个REXMLDataSource的类库工程的引用。
6.从上面ESRI.ArcGIS.ADF.Web.DataSources.REXMLData.config配置文件看,我们需要实现REXMLDataSource.GISDataSource、REXMLDataSource.MapResource这2个类。
7.新建GISDataSource.cs文件,具体的代码和说明如下:
2{
3 public class GISDataSource : IGISDataSource
4 {
5 private Hashtable m_state;
6 private string name = string.Empty;
7 private string dataSourceDefinition = string.Empty;
8 private string identity = string.Empty;
9 private Page page = null;
10 private GISResourceCollection resources = new GISResourceCollection();
11 bool _initialized = false;
12
13 public GISDataSource()
14 { }
15
16 public GISDataSource(string name, string identity, string dataSourceDefinition)
17 {
18 this.name = name;
19 this.identity = identity;
20 this.dataSourceDefinition = dataSourceDefinition;
21 }
22
23 public GISDataSource(string name, string dataSourceDefinition): this(name, string.Empty, dataSourceDefinition)
24 { }
25
26 //载入状态,IGISDataSource接口必须实现的方法
27 //从DataSourceManager关联的Hashtable载入状态
28 public void LoadState(Hashtable state)
29 {
30 m_state = state;
31 }
32
33 //初始化,IGISDataSource接口必须实现的方法
34 public void Initialize()
35 {
36 _initialized = true;
37 }
38
39 //保存状态,IGISDataSource接口必须实现的方法
40 public Hashtable SaveState()
41 {
42 return m_state;
43 }
44
45 //销毁,IGISDataSource接口必须实现的方法
46 public void Dispose()
47 {
48 _initialized = false;
49 }
50
51 //GISDataSource的名称,IGISDataSource接口必须实现的成员
52 public string Name
53 {
54 get { return name; }
55 set { name = value; }
56 }
57
58 //GISDataSource的定义,IGISDataSource接口必须实现的成员
59 //定义GIS data source信息,通常存储关于GIS data source的定位信息
60 public string DataSourceDefinition
61 {
62 get { return dataSourceDefinition; }
63 set
64 {
65 if (dataSourceDefinition != value)
66 {
67 dataSourceDefinition = value;
68 }
69 }
70 }
71
72 //GISDataSource的安全标识验证,IGISDataSource接口必须实现的成员
73 //连接GIS data source的用户认证标识
74 public string Identity
75 {
76 get { return identity; }
77 set { identity = value; }
78 }
79
80 //GISDataSource的Page,IGISDataSource接口必须实现的成员
81 public Page Page
82 {
83 get { return page; }
84 set { page = value; }
85 }
86
87 //GISDataSource的Resources,IGISDataSource接口必须实现的成员
88 public GISResourceCollection Resources
89 {
90 get { return resources; }
91 set { resources = value; }
92 }
93
94 //GISDataSource的状态,IGISDataSource接口必须实现的成员
95 //data source的状态存储,Resources和functionalities关联这个GIS data source的状态都被存储在这里,DataSourceManager控件会以哈希表存储所有的data source的状态
96 public Hashtable State
97 {
98 get
99 {
100 return m_state;
101 }
102 }
103
104 //GISDataSource的是否初始化标识,IGISDataSource接口必须实现的成员
105 public bool Initialized
106 {
107 get { return _initialized; }
108 }
109
110 //获取有效的ResourceDefinitions,IGISDataSource接口必须实现的方法
111 public string[] GetAvailableResourceDefinitions(System.Type resourceType)
112 {
113 throw new Exception("The method or operation is not implemented.");
114 }
115
116 //建立Resource,IGISDataSource接口必须实现的方法
117 public IGISResource CreateResource(string resourceDefinition, string name)
118 {
119 throw new Exception("The method or operation is not implemented.");
120 }
121 }
122
123}
124
2{
3 //MapResource实现IMapResource接口,而IMapResource实现了IGISResource接口,所以MapResource必须实现IMapResource和IGISResource的必要成员
4 public class MapResource : IMapResource
5 {
6 public MapResource() { }
7 public MapResource(string name, GISDataSource dataSource)
8 {
9 this.name = name;
10 this.dataSource = dataSource;
11 }
12
13 private GraphicsDataSet graphics = null;
14
15 public GraphicsDataSet Graphics
16 {
17 get { return graphics; }
18 }
19
20 private IMapInformation mapInformation = null;
21 private DisplaySettings displaySettings = null;
22
23 //IMapResource接口必须实现的成员,Map信息
24 public IMapInformation MapInformation
25 {
26 get { return mapInformation; }
27 set { mapInformation = value; }
28 }
29
30 //IMapResource接口必须实现的成员,地图显示设置
31 public DisplaySettings DisplaySettings
32 {
33 get { return displaySettings; }
34 set { displaySettings = value; }
35 }
36
37
38 bool initialized = false;
39 private string name = string.Empty;
40 private string resourceDefinition = string.Empty;
41 private IGISDataSource dataSource = null;
42 private GISFunctionalityCollection functionalities = new GISFunctionalityCollection();
43 private int validationtimeout = 0;
44
45 //IGISResource接口必须实现的成员,Resource初始化的超时时间
46 public int ValidationTimeout
47 {
48 get { return validationtimeout; }
49 set { validationtimeout = value; }
50 }
51
52 //IGISResource接口必须实现的成员,Resource名称
53 public string Name
54 {
55 get { return name; }
56 set { name = value; }
57 }
58
59 //IGISResource接口必须实现的成员,Resrouce定义字符串
60 public string ResourceDefinition
61 {
62 get { return resourceDefinition; }
63 set { resourceDefinition = value; }
64 }
65
66 //IGISResource接口必须实现的成员,Resource的Data Source
67 public IGISDataSource DataSource
68 {
69 get { return dataSource; }
70 set { dataSource = value; }
71 }
72
73 //IGISResource接口必须实现的成员,Resrource的Functionality集合
74 public GISFunctionalityCollection Functionalities
75 {
76 get { return functionalities; }
77 set { functionalities = value; }
78 }
79
80 //IGISResource接口必须实现的成员,判定是否支持各类的Functionality
81 public bool SupportsFunctionality(System.Type functionalityType)
82 {
83 if (functionalityType == typeof(ESRI.ArcGIS.ADF.Web.DataSources.IMapFunctionality))
84 {
85 return true;
86 }
87 else if (functionalityType == typeof(ESRI.ArcGIS.ADF.Web.DataSources.IMapTocFunctionality))
88 {
89 return true;
90 }
91 else if (functionalityType == typeof(ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality))
92 {
93 return true;
94 }
95 else
96 {
97 return false;
98 }
99 }
100
101 //IGISResource接口必须实现的成员,创建各种Functionality
102 public IGISFunctionality CreateFunctionality(System.Type functionalityType, string functionalityName)
103 {
104 IGISFunctionality gisfunctionality = null;
105 if (functionalityType == typeof(ESRI.ArcGIS.ADF.Web.DataSources.IMapFunctionality))
106 {
107 //MapFunctionality,具体见MapFunctionality.cs
108 gisfunctionality = new MapFunctionality(functionalityName, this);
109 }
110 else if (functionalityType == typeof(ESRI.ArcGIS.ADF.Web.DataSources.IMapTocFunctionality))
111 {
112 //MapTocFunctionality,具体见MapTocFunctionality.cs
113 gisfunctionality = new MapTocFunctionality(functionalityName, this);
114 }
115 else if (functionalityType == typeof(ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality))
116 {
117 //QueryFunctionality,具体见QueryFunctionality.cs
118 gisfunctionality = new QueryFunctionality(functionalityName, this);
119 }
120 else
121 {
122 throw new ArgumentException("functionalityType not supported");
123 }
124 return gisfunctionality;
125 }
126
127 //IGISResource接口必须实现的成员,是否初始化
128 public bool Initialized
129 {
130 get { return initialized; }
131 }
132
133 //IGISResource接口必须实现的成员,载入Data Source的状态
134 public void LoadState()
135 {
136 if (dataSource == null) return;
137 if (dataSource.State == null) return;
138
139 object o = dataSource.State[key];
140 if (o != null)
141 {
142 MapResource mr = o as MapResource;
143 graphics = mr.graphics;
144 mapInformation = mr.mapInformation;
145 displaySettings = mr.displaySettings;
146 }
147 }
148
149 //IGISResource接口必须实现的成员,初始化方法
150 public void Initialize()
151 {
152 if (mapInformation == null)
153 {
154 graphics = new GraphicsDataSet();
155 //设置Resorce的MapInformation,具体见MapInformation.cs
156 mapInformation = new MapInformation(graphics);
157 if (DisplaySettings != null)
158 {
159 //设置GraphicsDataSet的ImageDescriptor
160 graphics.ImageDescriptor = displaySettings.ImageDescriptor;
161 }
162 }
163 initialized = true;
164 //从Data Source定义中获取xml数据路径
165 string dataSourceConfig = DataSource.DataSourceDefinition;
166 //处理xml数据源
167 ProcessREXML(dataSourceConfig);
168 }
169
170 //IGISResource接口必须实现的成员,保存Resource的状态
171 public void SaveState()
172 {
173 if (dataSource == null) return;
174 if (dataSource.State == null) return;
175 dataSource.State[key] = this;
176 }
177
178 //IGISResource接口必须实现的成员,销毁方法
179 public void Dispose()
180 {
181 initialized = false;
182 }
183
184 //IGISResource接口必须实现的成员,清除Resource的状态
185 public void ClearState()
186 {
187 if (DataSource == null || DataSource.State == null) return;
188 DataSource.State[key] = null;
189 }
190
191 //本Resource存储在hashtable中的key
192 private string key
193 {
194 get
195 {
196 string tmp = this.GetType().ToString() + ":" + name;
197 return (tmp);
198 }
199 }
200
201 private void ProcessREXML(string dataSourceConfig)
202 {
203 try
204 {
205 //读取xml文件
206 XmlDocument doc = new XmlDocument();
207 doc.Load(dataSourceConfig);
208 XmlNode root = doc.DocumentElement;
209
210 //获取LAYER信息
211 XmlNode layerNode = root.SelectSingleNode("LAYER");
212 string layername = layerNode.Attributes.GetNamedItem("name").Value;
213 string layerid = layerNode.Attributes.GetNamedItem("id").Value;
214
215 ESRI.ArcGIS.ADF.Web.Display.Graphics.FeatureGraphicsLayer glayer = null;
216 bool gvisibility = true;
217
218 //从GraphicsDataSet查找名为layername FeatureGraphicsLayer,如果已有就记录显示状态并且清除layername FeatureGraphicsLayer
219 if (graphics.Tables.Contains(layername))
220 {
221 if (graphics.Tables[layername] is FeatureGraphicsLayer)
222 {
223 //记录显示状态
224 FeatureGraphicsLayer fgl = (FeatureGraphicsLayer)graphics.Tables[layername];
225 gvisibility = fgl.Visible;
226 }
227 //清除layername FeatureGraphicsLayer
228 graphics.Tables.Remove(layername);
229 }
230
231 //新见FeatureGraphicsLayer并设置属性
232 glayer = new ESRI.ArcGIS.ADF.Web.Display.Graphics.FeatureGraphicsLayer();
233 glayer.TableName = layername;
234 glayer.FeatureType = FeatureType.Point;
235 glayer.Visible = gvisibility;
236
237 //获取颜色、类型、宽、外边框颜色
238 XmlNode rendererNode = layerNode.SelectSingleNode("SIMPLERENDERER");
239 XmlNode markerNode = rendererNode.SelectSingleNode("SIMPLEMARKERSYMBOL");
240 string markercolor = markerNode.Attributes.GetNamedItem("color").Value;
241 string markertype = markerNode.Attributes.GetNamedItem("type").Value;
242 string markerwidth = markerNode.Attributes.GetNamedItem("width").Value;
243 string markeroutlinecolor = markerNode.Attributes.GetNamedItem("outlinecolor").Value;
244
245 //创建用来显示的图标
246 ESRI.ArcGIS.ADF.Web.Display.Symbol.SimpleMarkerSymbol sms = new ESRI.ArcGIS.ADF.Web.Display.Symbol.SimpleMarkerSymbol();
247
248 //rgb颜色
249 string[] markerrgb = markercolor.Split(',');
250 int markerr = Int32.Parse(markerrgb[0]);
251 int markerg = Int32.Parse(markerrgb[1]);
252 int markerb = Int32.Parse(markerrgb[2]);
253 //图标颜色
254 sms.Color = System.Drawing.Color.FromArgb(markerr, markerg, markerb);
255
256 //图标形状
257 switch (markertype)
258 {
259 case "circle":
260 sms.Type = ESRI.ArcGIS.ADF.Web.Display.Symbol.MarkerSymbolType.Circle;
261 break;
262 case "square":
263 sms.Type = ESRI.ArcGIS.ADF.Web.Display.Symbol.MarkerSymbolType.Square;
264 break;
265 case "triangle":
266 sms.Type = ESRI.ArcGIS.ADF.Web.Display.Symbol.MarkerSymbolType.Triangle;
267 break;
268 case "star":
269 sms.Type = ESRI.ArcGIS.ADF.Web.Display.Symbol.MarkerSymbolType.Star;
270 break;
271 default:
272 break;
273 }
274
275 int markerwidthInt;
276 if (!Int32.TryParse(markerwidth, out markerwidthInt))
277 {
278 markerwidthInt = 10;
279 }
280 //图标宽
281 sms.Width = markerwidthInt;
282
283 string[] markeroutrgb = markeroutlinecolor.Split(',');
284 int markeroutr = Int32.Parse(markeroutrgb[0]);
285 int markeroutg = Int32.Parse(markeroutrgb[1]);
286 int markeroutb = Int32.Parse(markeroutrgb[2]);
287 //图标外框颜色
288 sms.OutlineColor = System.Drawing.Color.FromArgb(markeroutr, markeroutg, markeroutb);
289
290 ESRI.ArcGIS.ADF.Web.Display.Renderer.SimpleRenderer sr = new ESRI.ArcGIS.ADF.Web.Display.Renderer.SimpleRenderer(sms);
291 glayer.Renderer = sr;
292
293 //获取FEATURES
294 XmlNode featuresNode = layerNode.SelectSingleNode("FEATURES");
295 XmlNodeList featureNodes = featuresNode.SelectNodes("FEATURE");
296
297 //获取SHAPE的字段属性建立GraphicElement
298 for (int t = 0; t < featureNodes.Count; ++t)
299 {
300 System.Data.DataRow datarow = null;
301
302 XmlNodeList flds = featureNodes[t].SelectNodes("FIELD");
303 for (int s = 0; s < flds.Count; s++)
304 {
305 // 如果是SHAPE就建立DataRow
306 if (flds[s].Attributes["name"].Value == "SHAPE")
307 {
308 XmlNodeList fldvalues = flds[s].SelectSingleNode("FIELDVALUE").ChildNodes;
309 if (fldvalues.Count < 1)
310 {
311 break;
312 }
313 else if (fldvalues.Count == 1)
314 {
315 XmlNode fldvalue = fldvalues[0];
316 if (fldvalue.Name == "POINT")
317 {
318 double dx = Double.Parse(fldvalue.Attributes["x"].Value);
319 double dy = Double.Parse(fldvalue.Attributes["y"].Value);
320
321 ESRI.ArcGIS.ADF.Web.Geometry.Point point = new ESRI.ArcGIS.ADF.Web.Geometry.Point(dx, dy);
322 datarow = glayer.Add(point);
323 }
324 }
325 else if (fldvalues.Count > 1)
326 {
327
328 }
329 }
330 else//否则作为属性
331 {
332
333 string fldname = flds[s].Attributes["name"].Value;
334 if (!glayer.Columns.Contains(fldname))
335 {
336 System.Data.DataColumn dcol = new System.Data.DataColumn("Status", System.Type.GetType("System.String"));
337 glayer.Columns.Add(dcol);
338 }
339 XmlNode fldvalue = flds[s].SelectSingleNode("FIELDVALUE");
340 string dvalue = fldvalue.Attributes["valuestring"].Value;
341 if ((dvalue != null) || (dvalue != String.Empty))
342 {
343 datarow[fldname] = dvalue;
344 }
345
346 }
347 }
348 }
349 //把生成的GraphicElement添加到GraphicsDataSet
350 graphics.Tables.Add(glayer);
351
352
353 }
354 catch (Exception ex)
355 {
356 throw new Exception("Exception: unable to load rexml data. " + ex.Message);
357
358 }
359
360 }
361 }
362}
363
9.MapResource类的几个主要方法执行顺序帮助理解:MapResource()->LoadState()->Initialize()->SupportsFunctionality()->CreateFunctionality()->SupportsFunctionality()->SaveState()->Dispose()
10.在MapResource类相关的MapInformation、MapFunctionality、MapTocFunctionality、QueryFunctionality4个类的实现可以参考Common_CustomDataSourceCSharp.zip样例,代码比较多比较简单这里就不详细说了。
11.xml数据内容如下:
13.在CustomDataSource的ASP.NET Web应用程序的Default_REXMLData.aspx页面中添加Map1、MapResourceManager1、Toc13个控件,然后做相应的设置,把上发布的usa的Map Service添加到MapResourceManager1中设置为ArcGIS Server Internet类型,名称为Server Resource,具体设置可以参考前面的文章。
14.接下来在MapResourceManager1中在Server Resource上面在新增加名为REXML Resource,在弹出的Map Resource Definition Editor中Type:选择REXML Data就是上面添加到DotNet文件内的ESRI.ArcGIS.ADF.Web.DataSources.REXMLData.config中定义的名字,在Data Source:输入上面的那个xml的地址,如:D:\rexml_point_wgs84.xml,然后确定就完成了设置。这里的Data Source为了方便是输入的方式了,最好的做法可以参考Common_CustomDataSourceCSharp.zip样例为它做一个xml文件选择界面,具体的参考CustomDataSource_CSharp\REXMLDataSource_CSharp\Design\DataSourceDefinitionEditorFormREXML.cs,是一个Winform的选择节目,只有在config文件配置一下,就可以在 Map Resource Definition Editor中调用自己定制的编辑器。
15.运行查看效果,可以看到在usa的地图上有4个绿色的五星,这4个5星就是从xml里定义的点。
16.通过自己实现GISData Source、MapResource、MapFunctionality的定义和实现就对ADF的WebControls、GISData Source、MapResource、MapFunctionality、具体的地图数据 这几者之间的关系就非常容易理解了,这样就让一些特殊的数据格也可以在ADF中使用了大大提高了数据的灵活性。