一个基于ArcGIS Mobile 9.3的GIS系统搭建方法

本文介绍如何使用 ArcGIS Mobile SDK 开发具备基本 GIS 功能的应用程序,涵盖地图显示、漫游、图层控制等功能,并提供代码示例。

 

接触ArcGIS Server 9.3已经有半年的时间了,主要使用ArcGIS Server中提供的Moible SDK开发一个GIS数据采集软件,半年来多多少少也对ArcGIS Mobile有了肤浅的了解,这篇文章主要是介绍一下如何使用Moible SDK开发一个具有基本GIS功能的系统,同时向即将使用ArcGIS Mobie进行开发工作的同学提供一点点的帮助。

ArcGIS MobileArcGIS Server 9.2中新加入的一个SDK,用来开发与ArcGIS Server服务式GIS平台无缝集成的Mobile应用程序,也可以运行在桌面计算机上。目前SDK最高版本为9.3,不过在ESRI今年发布的ArcGIS 10中会被升级到ArcGIS Mobile 10版本,具体的一些介绍可以到ESRI网站上去搜索。

据我所知,目前国内使用ArcGIS Mobile做开发的人和公司好像没有多少,毕竟是新东西,技术含量比较高,这一点从ESRI中国社区论坛上就可以看出来,零星的有人问个特简单的问题。 网上目前也有介绍ArcGIS Mobile开发的资料,比较推荐的是“牛魔王的作坊”,这个在百度里面搜索一下就能找到。好了,废话少说现在就开始简单的介绍一下这个小系统是如何实现的!!!

  1. 程序UI设计

比较经典的GIS系统通常要具备地图的显示、地图漫游功能、图层控制功能、属性查询以及量测工具等等。这些功能也是GIS系统最核心的基础功能。该系统界面主要使用了菜单栏、工具条、树控件、Map控件、DataGrid控件来搭建,下面看图:

菜单栏提供了程序中所有的功能,工具条提供了地图的平移、放大、缩小、属性查询的快捷方式,左侧的树控件提供了图层可见性的控制。、属性查询窗体中提供了选择地物的分类和元素的管理,当在左侧树控件中选择时将属性信息显示在右侧的表格中。

  1. 功能实现

在文件菜单中提供了“打开地图”命令,用于选择本地磁盘中的地图文件。由于ArcGIS Mobile是与ArcGIS Server无缝集成的,它所使用的数据源均为Server发布的服务,包括MapServiceGeoCodingGeoProcessing等等,所以本地磁盘的地图文件实际上是保存在磁盘上的地图缓存,它们是以.bin为结尾的。

地图缓存也可以通过ArcToolbox中提供的Mobile Tools制作。下面看代码:

  • 打开文件

在打开文件对话框中返回文件的绝对路径,使用FileInfoDirectoryInfo两个类获取文件的父路径。

private void OpenMapMenuItem_Click(object sender, EventArgs e)

{

string path = "";

 

if (openFileDialog1.ShowDialog() == DialogResult.OK)

{

string filename = openFileDialog1.FileName;

FileInfo file = new FileInfo(filename);

DirectoryInfo fileinfo = file.Directory;

path = fileinfo.ToString();

OpenMapFiles(path);//打开地图文件

map1.CurrentMapAction = panMapAction1;

}

}

OpenMapFiles()方法用来设置地图文件路径、URL,最后加载服务。

private void OpenMapFiles(string path)

{

try

{

mobileService1.Close();

mobileService1.CacheStoragePath = path;//设置缓存路径

mobileService1.Open(CacheOpenMode.Open);//加载缓存

PopLayers();

}

catch (FileNotFoundException ex)

{

MessageBox.Show(ex.Message, "提示", MessageBoxButtons.OK);

}

catch (OverflowException ex)

{

MessageBox.Show(ex.Message, "提示", MessageBoxButtons.OK);

}

}

PopLayers()方法用于向树控件中添加节点,节点的Text属性均被设置为图层名。

private void PopLayers()

{

treeView1.Nodes.Clear();

 

foreach (MapLayer layer in map1.MapLayers)

{

MobileServiceMapLayer mapLayer = layer as MobileServiceMapLayer;

 

if (mapLayer == null)

continue;

 

FeatureLayer feaLayer = mapLayer.Layer as FeatureLayer;

 

if (feaLayer == null)

continue;

 

string layerName = feaLayer.Name;

treeView1.Nodes.Add(layerName);

}

 

foreach (TreeNode node in treeView1.Nodes)

{

node.Checked = true;

}

}

这里要提一下,ArcGIS Mobile中的图层的概念和AE中的图层有些不一样,在AEMap控件下面包括的就是实际的图层,而Mobile使用的数据源均为服务器发布的服务,所以Map控件的MapLayers集合中存放的均为服务层,即MobileServiceLayer,它可以包括FeatureLayerRasterLayer等等,详细的说明可以查看开发文档,不过E文要好啊!

  •  地图浏览功能

地图的浏览功能其实都是Map控件提供的一些基本功能,我们注意一下Map控件的属性中有一项叫做“MapActions”,点击右侧的“...”按钮,可以看到MapActions集合编辑器,现在可以像集合中添加工具了,如下图:[图片]

下面我们使用这些基本功能,Map控件有一个CurrentMapAction属性,它可以设置Map控件的行为,我们可以在代码中进行操作。

//平移

private void PanMenuItem_Click(object sender, EventArgs e)

{

map1.CurrentMapAction = panMapAction1;

}

 

//放大

private void ZoomInMenuItem_Click(object sender, EventArgs e)

{

map1.CurrentMapAction = zoomInMapAction1;

}

 

//缩小

private void ZoomOutMenuItem_Click(object sender, EventArgs e)

{

map1.CurrentMapAction = zoomOutMapAction1;

}

 

//元素识别

private void IdentifyMenuItem_Click(object sender, EventArgs e)

{

map1.CurrentMapAction = selectionMapAction1;

selectionMapAction1.SelectionType = SelectionType.Point;

}

平移、放大、缩小功能只要将相应的值赋给CurrentMapAction就可以了,对于属性查询功能小比较来说就要麻烦点,首先要把地图的行为设置为选择,并且设置它的选择类型,可以点选、框选等等。回到上面的MapActions集合编辑器中,当向集合中添加selectionMapAction1项时,可以为它注册StatusChanged事件处理程序,当我们在地图上选择Features时,就会触发这个事件,这时我们可以从selectionMapAction1中获得所选择到的Features,剩下的就是现实数据的问题了!

//处理选择状态并弹出属性表

private GridForm grid;

private void selectionMapAction1_StatusChanged(object sender, MapActionStatusChangedEventArgs e)

{

if (e.StatusId != 1005)//判断选择的状态是否完成,很重要!

return;

 

if (selectionMapAction1.SelectedFeatures.Count < 1)

return;

 

List<FeatureDataTable> feaTables = selectionMapAction1.SelectedFeatures as List<FeatureDataTable>;

grid = new GridForm(feaTables,map1);

grid.Show();

}

当捕获到选择事件后,可以通过selectionMapAction1.SelectedFeatures返回选择到的元素,它们可以是不同图层的多个表!由于要在不同的窗体中共享数据,我在属性窗体中定义了一个非默认构造函数,用来传递集合和Map控件。

public GridForm(List<FeatureDataTable> tables,ESRI.ArcGIS.Mobile.Map map)

{

InitializeComponent();

tempTables = tables;

tempMap=map;

PopSelectedFeas();

}

 

//向树控件中填充选择到的元素类型和记录

private void PopSelectedFeas()

{

SelectionResultTreeView.Nodes.Clear();

 

//注意节点的层次性

foreach (FeatureDataTable tempTable in tempTables)

{

string tableName = tempTable.TableName;

TreeNode tempNode=SelectionResultTreeView.Nodes.Add(tableName);

 

foreach (FeatureDataRow tempRow in tempTable.Rows)

{

string rowID = tempRow.Fid.ToString();

tempNode.Nodes.Add(rowID);

}

}

}

由于我们在地图上选择的时候,无论是点选或是框选都有可能同时选择到很多的地物,所以要分别按类别把选择到的地物分类管理,填充到树控件中。

这时我们希望当点击某一个层时,能够显示所有这一层上的元素,当点击某一条记录时只显示这一条记录,因此要对点击的节点进行判断,判断的主要依据就是这个节点是有有父节点!

//当点击子节点时判断节点所在的表,找到相应的记录并在右侧表格中显示数据

private void SelectionResultTreeView_AfterSelect(object sender, TreeViewEventArgs e)

{

TreeNode selectedNode = e.Node;

string nodeName = selectedNode.Text;

 

if (selectedNode.Parent == null)

{

string layerName = nodeName;

 

//用来保存临时从表集合中寻找到的表

FeatureDataTable tempTinL = null;

foreach (FeatureDataTable feaTable in tempTables)

{

if (feaTable.TableName == layerName)

tempTinL = feaTable;

}

 

if(tempTinL!=null)

dataGridView1.DataSource = tempTinL;

}

else

{

TreeNode parentNode = selectedNode.Parent;

string layerName = parentNode.Text;

 

//用来保存临时从表集合中寻找到的表

FeatureDataTable tempTinL = null;

 

foreach (FeatureDataTable feaTable in tempTables)

{

if (feaTable.TableName == layerName)

tempTinL = feaTable;

}

 

int id = Convert.ToInt32(nodeName);

int fid=tempTinL.FidColumnIndex;

FeatureDataRow temp = null;

 

//寻找ID值与所选择记录ID相等的记录

foreach (FeatureDataRow tempRow in tempTinL.Rows)

{

if (Convert.ToInt32(tempRow[fid]) == id)

temp = tempRow as FeatureDataRow;

}

 

if (temp != null)

{

//复制表的结构而不是复制所有数据

DataTable table = tempTinL.Clone();

table.Rows.Add(temp.ItemArray);

dataGridView1.DataSource = table;

}

}

}

 

  • 工具

在这个菜单中提供了距离和面积量测功能,在实现的过程中为了简单起见,使用了Map控件的AddVertexSketchTool工具,这个工具会根据SketchGraphicLayerGeometry类型绘制不同的地物,不同的地物会提供如LengthArea等属性,这样很容易提取他们的距离和面积。同时还要注意这些结果使用的单位和制图时所使用的单位是一致的!我们无法更改。

//距离测量

private void LineMeaMenuItem_Click(object sender, EventArgs e)

{

ClearSketchGraphicLayer();

panelMeasure.Visible = true;

 

if (map1.CurrentMapAction != addVertexSketchTool1)

{

map1.CurrentMapAction = addVertexSketchTool1;

sketchGraphicLayer1.Geometry = new Polyline();//绘制的地物是线类型

}

else

{

sketchGraphicLayer1.Geometry = new Polyline();

}

 

tempGeometry = sketchGraphicLayer1.Geometry;

}

 

//面积测量

private void AreaMeaMenuItem_Click(object sender, EventArgs e)

{

ClearSketchGraphicLayer();

panelMeasure.Visible = true;

 

if (map1.CurrentMapAction != addVertexSketchTool1)

{

map1.CurrentMapAction = addVertexSketchTool1;

sketchGraphicLayer1.Geometry = new Polygon();//绘制的地物是面状的

}

else

{

sketchGraphicLayer1.Geometry = new Polygon();

}

 

tempGeometry = sketchGraphicLayer1.Geometry;

}

 

//清除绘制的临时Geometry

private void ClearSketchGraphicLayer()

{

if(sketchGraphicLayer1.Geometry!=null)

sketchGraphicLayer1.Geometry.Clear();//SketchGraphicLayer也是MapLayers集合中的一个层,用来保存绘制的元素,也可以被保存到实际的图层中

}

 

测量的结果显示在一个Panel上。

 

//显示测量结果面板

private void CalculateBtn_Click(object sender, EventArgs e)

{

if (tempGeometry.GeometryType == GeometryType.Polyline)

{

Polyline tempLine = tempGeometry as Polyline;

MeaResultLab.Text = tempLine.GetLength().ToString();//用来获取线的长度

}

else

{

Polygon tempArea = tempGeometry as Polygon;

MeaResultLab.Text = tempArea.GetArea().ToString();//用来获取面积

}

}

 

  • 图层管理器

图层管理器是用来控制图层的可见性、可选择性、可编辑性的工具,在该系统中只是简单的实现了图层的可见性,图层的可见性可以通过MapLayers[].Visible属性控制。

//动态的显示或关闭图层

private void treeView1_AfterCheck(object sender, TreeViewEventArgs e)

{

TreeNode selectedNode = e.Node;

bool nodeState=selectedNode.Checked?true:false;

string layerName=selectedNode.Text;

selectedLayer = mobileService1.Layers[layerName] as FeatureLayer;

 

if (nodeState)

{

map1.MapLayers[layerName].Visible = nodeState;

}

else

{

map1.MapLayers[layerName].Visible = nodeState;

}

}

3)总结

本文只是简单的把ArcGIS Mobile的功能做一个介绍,要想发挥Mobile的强大功能还需要结合ArcGIS Server来使用,例如我们可以为Windows Mobile系统的设备开发Mobile程序,在野外采集数据并实时的将数据回传到服务器,并且ArcGIS ServerSDE也是无缝集成的,所以后台的数据库可以是多版本的,这样数据冲突的问题也能得到很好的控制。

可参考的资源:http://resources.esri.com/arcgismobile/ ArcGIS Mobile资源中心

http://wu-yongfeng.blogspot.com/2008/08/arcgis-mobile-sdk-93.html 牛魔王的作坊,使用代理访问

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值