使用C#配合ArcGIS Engine进行地理信息系统开发


Posted in Python onFebruary 19, 2016

简单的地图读取、展示
终于到暑假了。。。开始认真整理整理相关学习的心得体会咯~
先把很久之前挖的关于C# 二次开发的坑给填上好了~ 这次先计划用一个月把C# ArcEngine 10.0相关开发的学习心得给发布出来好啦~

第一部分就是最简单的helloworld了:掌握使用控件创建简单的GIS应用程序~
(前期相关环境配置略掉~请自行百度~)

首先打开VS2010,,通过(文件--新建--项目--Windos窗体应用程序) ,我们新建一个名叫“MyHelloWorld”的Windows 窗体应用程序。然后就要开始往里面填控件了:
在 VS 的工具箱中找到到和 ArcGIS Engine 相关的控件 ,在这里我们使用AxTOCControl(目录控件),AxLicenseControl  (许可控件),以及MapControl,在这里MapControl对应于 ArcMap 中的数据视图,它封装了Map 对象,并提供了额外的属性,方法,事件等。是我们在接来下的一系列开发中必不可少的一环。
将3个控件排列一下后,效果如下图所示:

使用C#配合ArcGIS Engine进行地理信息系统开发

注意:
1.其中AxLicenseControl  控件是整个Arcengine开发中必须的许可控件,如果没有它或者没有ArcEngine的Lisence许可的话,我们是无法调用任何GIS功能的。
2.将三个控件拖入窗体后,我们会发现系统自动导入了相关引用,但无论是系统自己导入的引用还是我们手动导入的,请注意将引用属性中的“复制本地”设置为False,否则可能会产生无法运行代码的情况。
控件设置好之后,我们打开Program.cs,在系统的入口处添加这样一行代码:  

ESRI.ArcGIS.RuntimeManager.Bind(ESRI.ArcGIS.ProductCode.EngineOrDesktop);

这主要是针对Arcgis10.0的变化而设置的,添加后的代码如下:

namespace MyHelloWorld 
{ 
  static class Program 
  { 
    /// <summary> 
    /// The main entry point for the application. 
    /// </summary> 
    [STAThread] 
    static void Main() 
    { 
 
      ESRI.ArcGIS.RuntimeManager.Bind(ESRI.ArcGIS.ProductCode.EngineOrDesktop); 
      Application.EnableVisualStyles(); 
      Application.SetCompatibleTextRenderingDefault(false); 
      Application.Run(new Form1());

接下来,我们就可以通过设置编辑ToolbarControl的属性,来给它添加上我们需要的工具了,同时要记得在ToolBar控件和axTOCCControl1控件的属性设置中,将ToolBar的Buddy选项设置为axTOCCControl1,这样就可以将二者进行联动。
在ToolbarControl的属性设置中,我们可以通右键——属性——Item来给Toolbar控件设置我们需要的工具,在这里我选择了一些常用的工具:保存、移动、撤销、放大、缩小等等,过程如下图所示:

使用C#配合ArcGIS Engine进行地理信息系统开发

全部设置后之后,第一章的内容就基本结束了,将程序调试后,最终效果如下图,一个最简单的GIS桌面程序就出来啦~~

使用C#配合ArcGIS Engine进行地理信息系统开发

打开地图文档、鹰眼图的制作
首先是制作一个按钮来负责打开地图文档:
在toolbox中选择Button控件拖入我们的Form中,接下来在该button的Cilck事件中调用 OpenFileDialog类获取文件路径后,
 将文件路径调用到axMapControl1.LoadMxFile(path)中就可以打开MXD文档了。

private void button1_Click(object sender, EventArgs e) 
    { 
   OpenFileDialog OpenMXD = new OpenFileDialog(); 
   OpenMXD.Title = "打开地图"; 
   OpenMXD.InitialDirectory = "E:"; 
   OpenMXD.Filter = "Map Documents (*.mxd)|*.mxd"; 
   if (OpenMXD.ShowDialog() == DialogResult.OK) 
   { 
   string MxdPath = OpenMXD.FileName; 
   axMapControl1.LoadMxFile(MxdPath); 
<span style="white-space:pre">  </span>} 
    }

我们可以通过相同的方法打开shape文件,但是这里要注意:
axMapControl1.AddShapeFile()方法中,并不是像LoadMx一样直接输入文件路径就行,而是AddShapeFile(filePath, fileName),因此我们要先编写一个函数将文件路径的字符串进行分割:

private void button2_Click(object sender, EventArgs e) 
{ 
  { 
    string[] S = OpenShapeFile(); 
    try 
    { 
      axMapControl1.AddShapeFile(S[0], S[1]); 
    } 
    catch 
    { 
      MessageBox.Show("请至少选择一个shape文件", "ERROR"); 
     
     } 
 
    } 
  } 
 
 
public string[] OpenShapeFile() 
{ 
  string[] ShpFile = new string[2]; 
  OpenFileDialog OpenShpFile = new OpenFileDialog(); 
  OpenShpFile.Title = "打开Shape文件"; 
  OpenShpFile.InitialDirectory = "E:"; 
  OpenShpFile.Filter = "Shape文件(*.shp)|*.shp"; 
  if (OpenShpFile.ShowDialog() == DialogResult.OK) 
  { 
    string ShapPath = OpenShpFile.FileName; 
    //利用"\\"将文件路径分成两部分 
    int Position = ShapPath.LastIndexOf("\\"); 
    string FilePath = ShapPath.Substring(0, Position); 
    string ShpName = ShapPath.Substring(Position + 1); 
    ShpFile[0] = FilePath; 
    ShpFile[1] = ShpName; 
     
  } 
  return ShpFile; 
}

运行后结果如下:

使用C#配合ArcGIS Engine进行地理信息系统开发

这部分完成后,接下来是鹰眼图的制作~:

鹰眼图的操作主要分为两个部分,当在主控件中重新加载一幅图的时候,另外一个控件的图也发生相应的变化, 大致思路是在获得你在打开主地图后,向鹰眼图(MapControl2)中添加相同的图层,并不断更新你在主地图的当前范围,再在鹰眼图的对应区域中绘制一个红框表示对应范围。
这里主要使用了IEnvelope和IPoint接口,用来获取鼠标所在坐标、绘制表示范围的红框,具体用法可以参考这里~

我们在form中拖入第二个地图控件axMapControl2,用它作为axMapControl1的鹰眼图进行表示。
这里首先对MapControl1的OnMapReplaced事件和OnExtentUpdated事件进行编写,让我们获得MapControl1的地图范围更新,并向MapControl2添加图层、绘制矩形:

private void axMapControl1_OnExtentUpdated(object sender, ESRI.ArcGIS.Controls.IMapControlEvents2_OnExtentUpdatedEvent e) 
{ 
  //设置一个新的外接矩形 
  IEnvelope pEnvelope = (IEnvelope)e.newEnvelope; 
  IGraphicsContainer pGraphicsContainer = axMapControl2.Map as IGraphicsContainer; 
  IActiveView pActiveView = pGraphicsContainer as IActiveView; 
  //在绘制前,清除axMapControl2中的任何图形元素 
  pGraphicsContainer.DeleteAllElements(); 
  IRectangleElement pRectangleEle = new RectangleElementClass(); 
  IElement pElement = pRectangleEle as IElement; 
  pElement.Geometry = pEnvelope; 
  //设置鹰眼图中的红线框 
  IRgbColor pColor = new RgbColorClass(); 
  pColor.Red = 255; 
  pColor.Green = 0; 
  pColor.Blue = 0; 
  pColor.Transparency = 255; 
  //产生一个线符号对象 
  ILineSymbol pOutline = new SimpleLineSymbolClass(); 
  pOutline.Width = 3; 
  pOutline.Color = pColor; 
  //设置颜色属性 
  pColor = new RgbColorClass(); 
  pColor.Red = 255; 
  pColor.Green = 0; 
  pColor.Blue = 0; 
  pColor.Transparency = 0; 
  //设置填充符号的属性 
  IFillSymbol pFillSymbol = new SimpleFillSymbolClass(); 
  pFillSymbol.Color = pColor; 
  pFillSymbol.Outline = pOutline; 
  IFillShapeElement pFillShapeEle = pElement as IFillShapeElement; 
  pFillShapeEle.Symbol = pFillSymbol; 
  pGraphicsContainer.AddElement((IElement)pFillShapeEle, 0); 
  pActiveView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, null, null); 
  //将地图范围显示在StripStatus中 
  IPoint ll, Ur; 
  ll = axMapControl1.Extent.LowerLeft; 
  Ur = axMapControl1.Extent.LowerRight; 
  toolStripStatusLabel3.Text = "(" + Convert.ToString(ll.X) + "," + Convert.ToString(ll.Y) + ")"; 
 
} 

private void axMapControl1_OnMapReplaced(object sender, ESRI.ArcGIS.Controls.IMapControlEvents2_OnMapReplacedEvent e) 
{                                                                               //向MapControl2添加图层 
  if (axMapControl1.LayerCount > 0) 
  { 
    axMapControl2.Map = new MapClass(); 
    for (int i = 0; i <= axMapControl1.Map.LayerCount - 1; i++) 
    { 
       
      axMapControl2.AddLayer(axMapControl1.get_Layer(i)); 
    } 
    axMapControl2.Extent = axMapControl1.Extent; 
    axMapControl2.Refresh(); 
 
  } 
}

接下来就是对MapControl2控件的On_MouseDown 和 On_MouseMove事件进行编写,这样可以让我们通过拖动鹰眼图上的红框反向操作MapControl1中的地图位置:

private void axMapControl2_OnMouseMove(object sender, ESRI.ArcGIS.Controls.IMapControlEvents2_OnMouseMoveEvent e) 
    { 
      if (e.button == 1) 
      { 
        IPoint pPoint = new PointClass(); 
        pPoint.PutCoords(e.mapX, e.mapY); 
        axMapControl1.CenterAt(pPoint); 
        axMapControl1.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeography, 
        null, null); 
      } 
    } 
 
    private void axMapControl2_OnMouseDown(object sender, ESRI.ArcGIS.Controls.IMapControlEvents2_OnMouseDownEvent e) 
    { 
      if (axMapControl2.Map.LayerCount > 0) 
      { 
        if (e.button == 1) 
        { 
          IPoint pPoint = new PointClass();                                                             //将点击位置的坐标转换后设为MapControl1的中心 
          pPoint.PutCoords(e.mapX, e.mapY); 
          axMapControl1.CenterAt(pPoint); 
          axMapControl1.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeography, null, null); 
        } 
        else if (e.button == 2) 
        { 
          IEnvelope pEnv = axMapControl2.TrackRectangle(); 
          axMapControl1.Extent = pEnv; 
          axMapControl1.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeography, null, null); 
        } 
      } 
 
    }

最后在Form左下角再添加一个statusStrip控件,就可以实时显示当前图幅的范围了~
最终效果如下:

使用C#配合ArcGIS Engine进行地理信息系统开发

属性表的访问与显示
这里主要是访问并显示shapefile的属性表~

大致思路如下:新建一个Form用来获取选中要素的属性表,而在初始界面右键点击对应的矢量要素后,便打开新form将要素属性表展示出来。
下面就开始咯~
首先要添加ESRI.ArcGIS.Controls、Geodatabase的引用,更新命名空间;
然后我们添加一个用于显示属性表内容新的 Form 窗体,在这个新的窗体上添加 dataGridView 控件,并添加Column。

使用C#配合ArcGIS Engine进行地理信息系统开发

在Form2中,我们先将可能获得的属性表数据类型进行预定义:

public static string ParseFieldType(esriFieldType fieldType)//将EsriType 转换为String 
   { 
     switch (fieldType) 
     { 
       case esriFieldType.esriFieldTypeBlob: 
         return "System.String"; 
       case esriFieldType.esriFieldTypeDate: 
         return "System.DateTime"; 
       case esriFieldType.esriFieldTypeDouble: 
         return "System.Double"; 
       case esriFieldType.esriFieldTypeGeometry: 
         return "System.String"; 
       case esriFieldType.esriFieldTypeGlobalID: 
         return "System.String"; 
       case esriFieldType.esriFieldTypeGUID: 
         return "System.String"; 
       case esriFieldType.esriFieldTypeInteger: 
         return "System.Int32"; 
       case esriFieldType.esriFieldTypeOID: 
         return "System.String"; 
       case esriFieldType.esriFieldTypeRaster: 
         return "System.String"; 
       case esriFieldType.esriFieldTypeSingle: 
         return "System.Single"; 
       case esriFieldType.esriFieldTypeSmallInteger: 
         return "System.Int32"; 
       case esriFieldType.esriFieldTypeString: 
         return "System.String"; 
       default: 
         return "System.String"; 
     } 
   }

然后就是获取shpaefile的属性表了,这里我们主要使用 IField、IFeatureCursor、IFeature 这三个接口来达成目标:
接口说明如下:

  • IField 接口:用于获取要素表。
  • IFeature 接口:用来接收查询出来的要素。
  • IFeatureCursor 接口:通过Search进行查询,可以将结果保存在这里,从而利用NextFeature方法,遍历所有要素。

代码如下:

public void Opentable() 
    { 
      IFields pFields; 
      pFields = pFeaturelayer.FeatureClass.Fields; 
      dataGridView1.ColumnCount = pFields.FieldCount; 
      for (int i = 0; i < pFields.FieldCount; i++) 
      { 
        string fldName = pFields.get_Field(i).Name; 
        dataGridView1.Columns[i].Name = fldName; 
        dataGridView1.Columns[i].ValueType = System.Type.GetType(ParseFieldType(pFields.get_Field(i).Type)); 
      } 
      IFeatureCursor pFeatureCursor; 
      pFeatureCursor = pFeaturelayer.FeatureClass.Search(null, false); 
      IFeature pFeature; 
      pFeature = pFeatureCursor.NextFeature(); 
      while (pFeature != null) 
      { 
        string[] fldValue = new string[pFields.FieldCount]; 
        for (int i = 0; i < pFields.FieldCount; i++) 
        { 
          string fldName; 
          fldName = pFields.get_Field(i).Name; 
          if (fldName == pFeaturelayer.FeatureClass.ShapeFieldName) 
          { 
            fldValue[i] = Convert.ToString(pFeature.Shape.GeometryType); 
          } 
          else 
            fldValue[i] = Convert.ToString(pFeature.get_Value(i)); 
        } 
        dataGridView1.Rows.Add(fldValue); 
        pFeature = pFeatureCursor.NextFeature(); 
      } 
    }

搞定~接下来就是在初始界面选定要素后跳转界面显示属性表了~

先在form1中进行预定义:

IFeatureLayer pFeatureLayer = null; 
public IFeatureLayer pGlobalFeatureLayer; //定义全局变量 
public ILayer player;

因为决定在右击鼠标时显示选项,在Form1窗体中添加contextMenuStrip控件,添加选项”显示属性表“,在click事件中打开新form:

Form2 Ft = new Form2(player as IFeatureLayer); 
      Ft.Show();

然后就保证右键点击相关图层要素后能够成功打开对应属性表啦,这里主要用了TOCControl的 HitTest()方法:
publicvoid HitTest ( int X, int Y, ref esriTOCControlItem ItemType, ref IBasicMapBasicMap, ref ILayer Layer, ref object Unk, ref object Data );
其中

  • X,Y:鼠标点击的坐标;
  • ITemType:esriTOCControlItem枚举常量
  • BasicMap:绑定MapControl的IBasicMap接口
  • Layer:被点击的图层
  • Unk:TOCControl的LegendGroup对象
  • Data:LegendClass在LegendGroup中的Index。

在TOCControl控件的 OnMouseDown 事件下添加如下代码即可~:

if (axMapControl1.LayerCount > 0) 
{ 
  esriTOCControlItem pItem = new esriTOCControlItem(); 
  pGlobalFeatureLayer = new FeatureLayerClass(); 
  IBasicMap pBasicMap = new MapClass(); 
  object pOther = new object(); 
  object pIndex = new object(); 
  axTOCControl1.HitTest(e.x, e.y, ref pItem, ref pBasicMap, ref player, ref pOther, ref pIndex); 
} 
if (e.button == 2) 
{ 
  contextMenuStrip1.Show(axTOCControl1, e.x, e.y); 
}

大功告成~~
运行结果如下:
右击显示属性表:

使用C#配合ArcGIS Engine进行地理信息系统开发

点击后出现属性表~~~:

使用C#配合ArcGIS Engine进行地理信息系统开发

Python 相关文章推荐
python获取糗百图片代码实例
Dec 18 Python
python爬虫获取多页天涯帖子
Feb 23 Python
浅谈python之新式类
Aug 12 Python
Python 变量类型详解
Oct 10 Python
如何通过雪花算法用Python实现一个简单的发号器
Jul 03 Python
python3.x提取中文的正则表达式示例代码
Jul 23 Python
pycharm 批量修改变量名称的方法
Aug 01 Python
python文件读写代码实例
Oct 21 Python
关于python中的xpath解析定位
Mar 06 Python
tensorflow基于CNN实战mnist手写识别(小白必看)
Jul 20 Python
python IP地址转整数
Nov 20 Python
Python Pandas解析读写 CSV 文件
Apr 11 Python
Python中使用OpenCV库来进行简单的气象学遥感影像计算
Feb 19 #Python
Python实现以时间换空间的缓存替换算法
Feb 19 #Python
Python使用爬虫猜密码
Feb 19 #Python
使用Python简单的实现树莓派的WEB控制
Feb 18 #Python
在Ubuntu系统下安装使用Python的GUI工具wxPython
Feb 18 #Python
以一个投票程序的实例来讲解Python的Django框架使用
Feb 18 #Python
使用Python生成随机密码的示例分享
Feb 18 #Python
You might like
用PHP读注册表
2006/10/09 PHP
PHP is_dir() 判断给定文件名是否是一个目录
2010/05/10 PHP
百万级别知乎用户数据抓取与分析之PHP开发
2015/09/28 PHP
thinkPHP中验证码的简单使用方法
2015/12/26 PHP
mysql_escape_string()函数用法分析
2016/04/25 PHP
PHP 输出缓冲控制(Output Control)详解
2016/08/25 PHP
Zend Framework路由器用法实例详解
2016/12/11 PHP
laravel 实现用户登录注销并限制功能
2019/10/24 PHP
AutoSave/自动存储功能实现
2007/03/24 Javascript
jQuery AJAX 调用WebService实现代码
2010/03/24 Javascript
js中对象的声明方式以及数组的一些用法示例
2013/12/11 Javascript
使用js判断当前时区TimeZone是否是夏令时
2014/02/23 Javascript
php,js,css字符串截取的办法集锦
2014/09/26 Javascript
JS中使用gulp实现压缩文件及浏览器热加载功能
2017/07/12 Javascript
Echarts之悬浮框中的数据排序问题
2018/11/08 Javascript
微信小程序之事件交互操作实例分析
2018/12/03 Javascript
JavaScript碎片—函数闭包(模拟面向对象)
2019/03/13 Javascript
微信小程序3种位置API的使用方法详解
2019/08/05 Javascript
浅析Vue 防抖与节流的使用
2019/11/14 Javascript
JavaScript实现左右滚动电影画布
2020/02/06 Javascript
vue-router 路由传参用法实例分析
2020/03/06 Javascript
JavaScript实现世界各地时间显示
2020/09/07 Javascript
win与linux系统中python requests 安装
2016/12/04 Python
MySQL适配器PyMySQL详解
2017/09/20 Python
微信跳一跳python代码实现
2018/01/05 Python
详解python中的线程
2018/02/10 Python
Python简易版图书管理系统
2019/08/12 Python
python pandas dataframe 去重函数的具体使用
2020/07/20 Python
python实现快速文件格式批量转换的方法
2020/10/16 Python
python 爬取百度文库并下载(免费文章限定)
2020/12/04 Python
解决img标签上下出现间隙的方法
2016/12/14 HTML / CSS
HTML5在微信内置浏览器下右上角菜单的调整字体导致页面显示错乱的问题
2021/01/19 HTML / CSS
Tretorn美国官网:瑞典外套和鞋类品牌,抵御风雨
2018/07/19 全球购物
巾帼建功标兵事迹材料
2014/05/11 职场文书
毕业生找工作求职信
2014/08/05 职场文书
淘宝好评语句大全
2014/12/31 职场文书