本次题目分为上下集分别进行叙述,上集为1-6题较难,下集7-10较为简单
一、系统需求
根据你的解决方案,开发一个应用型GIS系统,该系统需要具备以下功能:
(1)打开地图文档功能
(2)退出程序并保存地图文档功能。
(3)在地图上点击,选择一个监测站点,并显示该监测站点的属性信息。
(4)在监测站点列表中选择一个监测站点后,在地图上高亮显示,缩放至该监测站点,并显示该监测站点的属性信息。
(5)在地图上选择一个多边形,统计该多边形内部的监测站点内数量,并高亮显示。
(6)将Excel中的数据匹配到监测站点。
(7) 在地图上显示北京各个区县的名称。
(8)为北京各个区县匹配一个符号。
(9)导出北京区县图层为一个新的数据。
(10)在监测站点图层添加一个新站点。
注:需提交GIS应用系统的源码文件和可执行应用程序。
二、界面设计
三、功能分析
3.1 地图文档的基础操作(打开、保存、另存为、退出)
我是直接用的AE自带模板,打开VS2015界面,【文件】—>【新建】—>【项目】,选择【VIsual C#】–>【ArcGIS 】–>【Extending ArcObjects】–>选中【MapControl Application】,点击【确定】,如图一所示,便可创建出MapControl Application模板,该模板自带打开、新建、另存为、退出地图文档功能。
图一 新建MapControl Application界面
3.2 在地图上点击,选择一个监测站点,并显示该监测站点的属性信息
3.3在地图上选择一个多边形,统计该多边形内部的监测站点内数量,并高亮显示。
这两个功能是通过主菜单上名为【选择要素并显示其属性】的菜单项实现的
功能我是选择的是调用要素选择工具以及axMapControl1的axMapControl1_OnMouseUp()实现,当我们点击主菜单的菜单项【选择要素并显示其属性】时,进入它的Click()函数,调取要素选择工具,此时去点击要查询要素,(这个可以点击也可以框选,故也可以实现选择一个多边型),这时候你是在axMapControl1的界面点击,当你鼠标松开时,就该调取axMapControl1_OnMouseUp(),在axMapControl1_OnMouseUp()调取FormSelection.cs窗体,FormSelection.cs窗体是实现显示选择要素的属性以及个数。此时我们还要记得,人家我们在框选中肯定会选到【北京区县界面图层】,所以这个问题我们在获取地图文档的FeatureLayer中就将【北京区县界面图层】这个FeatureLayer.Selectable=false,这是就可以解决问题。
//主界面中,如何是直接创建的模板,主界面窗体名为MainForm.cs
#region 获取数据列表的FeatureLayer
//pFeatLayer (北京区县)、goalFeatLayer (监测站)是全局变量,因为这两个FeatureLayer很重要,
// 地图文档就这俩图层,没图层我们能干成什么事!!
// 我们根据图层名称获取FeatureLayer
public IFeatureLayer goal_Flayer(IMap pMap)
{
for (int i = 0; i < pMap.LayerCount; i++)
{
if (pMap.get_Layer(i) is IFeatureLayer)
{
string name = pMap.get_Layer(i).Name;
if (name == "北京区县界")
{
//不对北京区县界进行操作
pFeatLayer = pMap.get_Layer(i) as IFeatureLayer;
pFeatLayer.Selectable = false;
}
if (name == "监测站")
{
goalFeatLayer = pMap.get_Layer(i) as IFeatureLayer;
}
}
}
return goalFeatLayer;
}
#endregion
```csharp
//此函数是你双击菜单项【选择要素并显示其属性】系统自动生成的函数,当你点击此菜单项时会进入(触发)此函数,执行函数里的功能
#region 当选择要素并显示其属性菜单项进入该函数
private void 选择要素并显示其属性ToolStripMenuItem1_Click(object sender, EventArgs e)
{
try
{
//首先清空地图选择集,以进行后续的选择操作
axMapControl1.Map.FeatureSelection.Clear();
pMap = axMapControl1.Map;
goal_Flayer(pMap);
#region 要素选择 调用工具 ControlsSelectFeaturesTool
axMapControl1.CurrentTool = null;
ControlsSelectFeaturesTool pTool = new ControlsSelectFeaturesToolClass();
pTool.OnCreate(axMapControl1.Object);
axMapControl1.CurrentTool = pTool as ITool;
#endregion
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
#endregion
此时选择要素已经不成问题了,接下来实现点击后就显示其属性信息,axMapControl1_OnMouseUp()函数也是自动生成的,这个是点击axMapControl控件,选择属性,点击闪电按钮,也就是事件,找到该事件,双击即可,就自动生成了以下函数了,在C#窗体应用程序中,这个一定要注意
#region 显示选择的要素属性 单击后鼠标松开后进入该事件
private void axMapControl1_OnMouseUp(object sender, IMapControlEvents2_OnMouseUpEvent e)
{
//新创建地图选择集窗体
FormSelection formSelection = new FormSelection();
//将当前主窗体中MapControl控件中的Map对象赋值给FormSelection窗体的CurrentMap属性
// 通过访问器 值得注意
formSelection.CurrentMap = axMapControl1.Map;
//显示地图选择集窗体
formSelection.Show();
}
#endregion
FormSelection.cs窗体,设计如图二
图二 FormSelection.cs窗体设计
FormSelection.cs代码
using System;
using System.Windows.Forms;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Geodatabase;
namespace Selection
{
public partial class FormSelection : Form
{
private IMap currentMap; //当前MapControl控件中的Map对象
private IFeatureLayer currentFeatureLayer; //设置临时类变量来使用IFeatureLayer接口的当前图层对象
/// <summary>
/// 获得当前MapControl控件中的Map对象
/// </summary>
//类中的私有(private)变量不能直接赋值,C#使用 访问器(accessors) 让私有域的值可被读写或操作。
//C#中 通过 访问器 访问属性
//属性(Property)的访问器(accessor)包含有助于获取(读取或计算)或设置(写入)属性的可执行语句。
//访问器(accessor)声明可包含一个 get 访问器、一个 set 访问器,或者同时包含二者。
//固定的格式 public 类型 所设置访问器的属性
//这样可以让另一个窗口对这个窗口的属性赋值
public IMap CurrentMap
{
set
{
currentMap = value;
}
}
public FormSelection()
{
InitializeComponent();
}
//在窗体加载时执行本函数,加载所有具有选择要素的图层
private void FormSelection_Load(object sender, EventArgs e)
{
IFeatureLayer featureLayer; //设置临时变量存储当前矢量图层
string layerName; //设置临时变量存储当前图层的名称
TreeNode treeNode; //设置临时变量存储当前树节点的信息
//对Map中的每个图层进行判断并加载图层名称
for (int i = 0; i < currentMap.LayerCount; i++)
{
//如果该图层为图层组类型,则分别对所包含的每个图层进行操作
if (currentMap.get_Layer(i) is GroupLayer)
{
//使用ICompositeLayer接口进行遍历操作
ICompositeLayer compositeLayer = currentMap.get_Layer(i) as ICompositeLayer;
for (int j = 0; j < compositeLayer.Count; j++)
{
//得到图层的名称
layerName = compositeLayer.get_Layer(j).Name;
//得到矢量图层对象的IFeatureLayer接口
featureLayer = (IFeatureLayer)compositeLayer.get_Layer(j);
//如果该图层选择集中的要素不为空,则在TreeView控件中添加一个树节点
if (((IFeatureSelection)featureLayer).SelectionSet.Count > 0)
{
//新建一个树节点,将图层名称作为树节点的名称
treeNode = new TreeNode(layerName);
//利用树节点的Tag属性,存储当前图层的IFeatureLayer接口信息
treeNode.Tag = featureLayer;
//将新建的树节点添加到TreeView控件中的根节点下
treeViewLayers.TopNode.Nodes.Add(treeNode);
}
}
}
//如果图层不是图层组类型,则同样在TreeView控件中的根节点下添加节点
else
{
layerName = currentMap.get_Layer(i).Name;
featureLayer = (IFeatureLayer)currentMap.get_Layer(i);
if (((IFeatureSelection)featureLayer).SelectionSet.Count > 0)
{
treeNode = new TreeNode(layerName);
treeNode.Tag = featureLayer;
treeViewLayers.TopNode.Nodes.Add(treeNode);
}
}
}
//添加完节点后将根节点展开以显示所有的图层
treeViewLayers.TopNode.Expand();
//通过IMap接口的SelectionCount属性可以获取被选择要素的数量
labelMapSelectionCount.Text = "当前地图共选择了 " + currentMap.SelectionCount + " 个要素。";
}
//在图层被选中时执行本函数,完成该图层所有选中要素的列表
private void treeView_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
try
{
//首先清空DataGridView中的行和列
dataGridView.Columns.Clear();
dataGridView.Rows.Clear();
//通过树节点的Tag属性获取以该节点名称命名的矢量图层
currentFeatureLayer = e.Node.Tag as IFeatureLayer;
//通过接口转换,使用IFeatureSelection接口获取图层的选择集
IFeatureSelection featureSelection = currentFeatureLayer as IFeatureSelection;
//通过ISelectionSet接口获取被选择的要素集合
ISelectionSet selectionSet = featureSelection.SelectionSet;
//通过ISelectionSet接口的Count属性可以获取被选择要素的数量
labelLayerSelectionCount.Text = "当前图层选择了 " + selectionSet.Count + " 个要素。";
//对当前图层要素的属性字段进行遍历,从而建立DataGridView中的列
//获取所有的属性字段
IFields fields = currentFeatureLayer.FeatureClass.Fields;
for (int i = 0; i < fields.FieldCount; i++)
{
//通过遍历添加列,使用字段的AliasName作为DataGridView中显示的列名
dataGridView.Columns.Add(fields.get_Field(i).Name, fields.get_Field(i).AliasName);
}
//对选择集进行遍历,从而建立DataGridView中的行
//定义ICursor接口的游标以遍历整个选择集
ICursor cursor;
//使用ISelectionSet接口的Search方法,使用null作为查询过滤器,cursor作为返回值获取整个选择集
selectionSet.Search(null, false, out cursor);
//进行接口转换,使用IFeatureCursor接口来获取选择集中的每个要素
IFeatureCursor featureCursor = cursor as IFeatureCursor;
//获取IFeature接口的游标中的第一个元素
IFeature feature = featureCursor.NextFeature();
//定义string类型的数组,以添加DataGridView中每一行的数据
string[] strs;
//当游标不为空时
while (feature != null)
{
//string数组的大小为字段的个数
strs = new string[fields.FieldCount];
//对字段进行遍历
for (int i = 0; i < fields.FieldCount; i++)
{
//将当前要素的每个字段值放在数组的相应位置
strs[i] = feature.get_Value(i).ToString();
}
//在DataGridView中添加一行的数据
dataGridView.Rows.Add(strs);
//移动游标到下一个要素
feature = featureCursor.NextFeature();
}
}
catch { }
}
}
}
结果展示
当程序运行成功时,点击主菜单【选择要素并显示其属性】,便可以在屏幕中选择点击某个监测站点可以直接用鼠标框选站点,鼠标点击结束后,框选的点自动高亮显示并自动弹出界面显示被选择监测站点的属性信息及其数目。在此以框选为例,结果如图3-4所示。框选结果可以通过工具栏【Clear Selected Feature】可以清除,该工具如图5所示。
图3 鼠标框选
图4 鼠标框选结果
图5 清除选择要素工具
3.4 在监测站点列表中选择一个监测站点后,在地图上高亮显示,缩放至该监测站点,并显示该监测站点的属性信息。
功能实现 点击【显示监测站点属性表】
功能分析 显示其属性表,在属性表的某一行单击,在地图上高亮显示以及缩放至该监测站点
我们设置了一个窗体【FormAtrribute】,该窗体只有一个控件就是DataGridView,我们要获取要素图层的属性,并且我们点击某一行时,高亮显示并缩放至该监测站点
FormAtrribute.cs 代码
using System;
using System.Data;
using System.Windows.Forms;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Geometry;
namespace Atrribute
{
public partial class FormAtrribute : Form
{
//要查询的属性图层 成员变量
private IFeatureLayer _curFeatureLayer;
private IActiveView act = null;
private DataTable dataTable = null;
// 不同的构造函数对应不同要求
// 名称是类名 下面是系统自动生成的
public FormAtrribute()
{
InitializeComponent();
}
public void changeDataSource(DataTable s)
{
this.dataGridAttribute.DataSource = s;
}
//应我们需求产生 我们在主界面代码中已经把excel转变为Datatable了 现在我们需要把DataTable与我们目标图层产生联系
//故构造了下面的构造函数
public FormAtrribute(DataTable dt, IFeatureLayer layer)
{
InitializeComponent();
this.dataTable = dt;
this._curFeatureLayer = layer;
}
//类中的私有(private)变量不能直接赋值,C#使用 访问器(accessors) 让私有域的值可被读写或操作。
//C#中 通过 访问器 访问属性
//属性(Property)的访问器(accessor)包含有助于获取(读取或计算)或设置(写入)属性的可执行语句。
//访问器(accessor)声明可包含一个 get 访问器、一个 set 访问器,或者同时包含二者。
//固定的格式
public IFeatureLayer CurFeatureLayer
{
get { return _curFeatureLayer; }
set { _curFeatureLayer = value; }
}
public IActiveView ActiveView
{
get { return act; }
set { act = value; }
}
#region 创建属性表(通用型)
DataTable pFeatDT = new DataTable(); //创建数据表
DataRow pFDataRow = null; //数据表行变量
DataColumn pFDataCol = null; //数据表列变量
IField pField = null;
public void InitUI()
{
if (_curFeatureLayer == null) return;
IFeature pFeature = null;
for (int i = 0; i < _curFeatureLayer.FeatureClass.Fields.FieldCount; i++)
{
pFDataCol = new DataColumn();
pField = _curFeatureLayer.FeatureClass.Fields.get_Field(i);
pFDataCol.ColumnName = pField.AliasName; //获取字段名作为列标题
pFDataCol.DataType = Type.GetType("System.Object");//定义列字段类型
pFeatDT.Columns.Add(pFDataCol); //在数据表中添加字段信息
}
IFeatureCursor pFeatureCursor = _curFeatureLayer.Search(null, true);
pFeature = pFeatureCursor.NextFeature();
while (pFeature != null)
{
pFDataRow = pFeatDT.NewRow();
//获取字段属性
for (int k = 0; k < pFeatDT.Columns.Count; k++)
{
pFDataRow[k] = pFeature.get_Value(k);
}
pFeatDT.Rows.Add(pFDataRow); //在数据表中添加字段属性信息
pFeature = pFeatureCursor.NextFeature();
}
//释放指针
System.Runtime.InteropServices.Marshal.ReleaseComObject(pFeatureCursor);
dataGridAttribute.DataSource = pFeatDT;
}
#endregion
#region 单击要素属性表行号放缩至该要素区域
private void dataGridAttribute_RowHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
act.FocusMap.ClearSelection();
//获取行号
int i = e.RowIndex;
//根据行号获取要素
IFeature feature = _curFeatureLayer.FeatureClass.GetFeature(i);
IPoint pt = new PointClass();
IGeometry geo = feature.Shape;
IGeometry5 geo5 = geo as IGeometry5;
//获取该要素的中心点坐标
pt.X = geo5.CentroidEx.X;
pt.Y = geo5.CentroidEx.Y;
IEnvelope env = new EnvelopeClass();
//以该坐标为基础创建包络线
env.XMax = pt.X + 0.01;
env.XMin = pt.X - 0.01;
env.YMax = pt.Y + 0.01;
env.YMin = pt.Y - 0.01;
env.CenterAt(pt);
env.Expand(0.01, 0.01, false);
//将地图的显示区域设置为创建的包络线 即放缩至该要素
act.Extent = env;
//同时高亮
act.FocusMap.SelectByShape(pt as IGeometry, null, true);
act.Refresh();
}
#endregion
#这是将两个表结合起来 Excel匹配站点会用到
public void Join()
{
pFeatDT.Columns.Add("PM2.5", typeof(Int32));
pFeatDT.Columns.Add("SO2", typeof(Int32));
pFeatDT.Columns.Add("NO2", typeof(Int32));
foreach (DataRow Ftemprow in pFeatDT.Rows)
{
foreach(DataRow temprow in dataTable.Rows)
{
if(Ftemprow["Name"].ToString() == temprow["站点名称"].ToString() )
{
Ftemprow["PM2.5"] = int.Parse(temprow["PM2#5"].ToString());
Ftemprow["SO2"] = int.Parse(temprow["SO2"].ToString()) ;
Ftemprow["NO2"] = int.Parse(temprow["NO2"].ToString());
}
}
}
dataGridAttribute.DataSource = pFeatDT;
}
}
}
【显示监测站点属性表】的Click(),调取该窗体即可
private void 打开监测站点属性表ToolStripMenuItem_Click(object sender, EventArgs e)
{
pMap = axMapControl1.Map;
FormAtrribute pAtrribute = new FormAtrribute();
pAtrribute.CurFeatureLayer = goal_Flayer(pMap);
pAtrribute.ActiveView = axMapControl1.ActiveView;
pAtrribute.InitUI();
pAtrribute.ShowDialog();
}
运行结果
当程序运行成功时,点击主菜单【显示监测站属性表】,便自动弹出监测站属性表界面,结果如图6
图6【显示监测站属性表】运行结果
3.5Excel中的数据匹配到监测站点
功能分析 我们这里要先知道Excel如何读取并且转化为DataTable,需要注意下图
功能实现 点击【Excel匹配站点】
功能分析 关于两个表Join的代码在窗体【FormAtrribute】已经写过,不再赘述,此处只写,【Excel匹配站点】的Click()
private void excel数据匹配站点ToolStripMenuItem_Click(object sender, EventArgs e)
{
OpenFileDialog open = new OpenFileDialog();
open.Title = "打开Excel表";
open.Filter = "Excel2003(*.xls)|*.xls";
if (open.ShowDialog() == DialogResult.OK)
{
//Excel路径
string path = open.FileName;
// 采用OleDB读取EXCEL文件:
//把EXCEL文件当做一个数据源来进行数据的读取操作
//OLEDB 是 Microsoft 的数据访问模型。
//数据库连接字符串
string strConn = "Provider=Microsoft.Jet.OLEDB.4.0;" + "Data Source=" + path + ";"
+ "Extended Properties='Excel 8.0;HDR=Yes;IMEX=1';";
//表名
string sheetName = "Sheet1";
//选择语句
string select = "Select * from [" + sheetName + "$]";
//创建连接
OleDbConnection conn = new OleDbConnection(strConn);
//开启连接
conn.Open();
//创建适配器
OleDbDataAdapter adapter = new OleDbDataAdapter(select, strConn);
DataTable dt = new DataTable();
//填充数据
adapter.Fill(dt);
//关闭连接 现在已经将excel转化成D数据表了
conn.Close();
#region 查看我们导入的excel
//pAtrribute.changeDataSource(dt);
#endregion
pMap = axMapControl1.Map;
FormAtrribute pAtrribute = new FormAtrribute(dt, goalFeatLayer);
pAtrribute.CurFeatureLayer = goal_Flayer(pMap);
pAtrribute.ActiveView = axMapControl1.ActiveView;
pAtrribute.InitUI();
pAtrribute.Join();
pAtrribute.ShowDialog();
}
}
当程序运行成功时,点击主菜单【Excel数据匹配站点】,便自动弹出打开打开Excel表对话框,选择目标Excel表(后缀为.xls),结果如图7所示,点击【打开】,便会将Excel中的数据匹配到监测站点并以表的形式呈现我们面前,结果如图8所示。
图7选择目标Excel表
图8 将表格Excel中的数据匹配到监测站点