当前位置:文档之家› Engine 开发手册(1)

Engine 开发手册(1)

一ArcGIS介绍 1
1、1ArcGIS Engine 中的类库 5
1、2 和ArcGIS Engine开发相关的C#知识
1、2、1接口 编程
1、3C#接 口的 例子
1、3、1快速 掌握 OMD
1、4快速 理解 Q I

二. 使用控件创建第一个桌面应用程序
2、1代 码加 载 Mxd 文档
2、2添加 Shape 文 件
2、3庖丁 解牛 识控 件
2、4第一 个控 件 MapControl
2、5变主动为被动-出接口(OutBound interface)
2、6鹰眼图的实现
2、7 TOCContro 控 件
2、8显示属性表的信息
2、9命令 和工 具的 宿主控 件 ToolBarControl 控 件
2、10命令和工具
2、11脱离 ToolBarControl 控件 的命 令和 工具
2、12另一 个视 图控 件 PageLayoutControl
2、13 MapControl 控件与 PageLayout 控件的联动
2、14第一个对象 Map
2、15使用IMap.SelectFeature方法对地图中的要素进行查询

四. 空间 数据 库
4.1 Geodatabase 介绍
4.2 Geodatabase 统一的存储框架
4、3 IWorkSpace 接 口 介绍
4、3、1 如何 打开 一个 数据库
4、3、2打开个人数据库
4、3、3打开文件数据库
4、3、4打开 SDE 数据库
4、4如何 获取 数据 库中的 所有要素类
4、4、1深入理解数据集
4、4、2获取数据库中的要素类
4、5峰回 路转 打开 数据库 的另一种方式
4、5、1 IName(名称对象)介绍
4、6如何 删除 要素 类
4、6、1 IFeatureWorkspace接 口介 绍
4、7如何 创建 一个 要素数 据类
4、8 IField,IFieldEdit,I Fields,IFieldsEditI,GeometryDef,IGeometryDefEdit 接口
4、9如何 改变 字段 的别名
4、10栅格 数据 管理
4、10、1打开 栅格 数据
4、10、2打开 栅格 目录 中的一 个数据
4、10、3创建 栅格 数据 集
4、11打开 镶嵌 数据 集
4、12创建 一个 镶嵌 数据集
4、13和查 询相 关的 对象和 接口
4、14 false 和 true 参数的差别
4、15 Search 和 Select 方法的比较
4、16 Cursor 和 FeatureCursor 对象

4、17 QueryFilter 与 SpatialFilter 对象
4、18 IFeatureSelection 接 口
4、19使用 I FeatureSelection 接口高亮显示
4、20空间 查询
4、21附件 功能
4、22和附 件相 关的 接口
4、23综合 例子 空间 查询和 创建 Table
4、24 数据 转换
4、25 Querylayer
4、26使用 查询 图层 快速浏 览

五. 几何对象和空间参考
5、1点和 多点
5、2 Segment,path,ring和Polyline的区别
5、3Envelope 几何 对象
5、4 Curve 对 象几 何 对象
5、5 Multi patch 几何 对象
5、6 Geometry 集 合 接口
5、7空间 参考

六. 矢量 数据 空间分析
6、1叠加 分析
6、2关系 操作
6、3临近 操作
6、4拓扑 关系 操作
6、5空间 插值
6、6开发 利器 GP

七. 符号 化
7、1和符 号化 相关 的对象
7、2符号 对象
7、3专题 图制 作
7、4唯一 值
7、5分类 图
7、6比例 图
7、7简单


7、8饼图
7、9点状 图
7、10柱状 图

八. 栅格 数据 分析
8、1两个 扩展 模块
8、2栅格 分析 的通 常步骤
8、3空间 分析
8、4和栅 格空 间分 析的相 关接口
8、5重要 名词 (表 面、栅格 表面、TIN表面)
8、6表面 分析
8、7专属于空间 分析的 表面分析(邻域 分析 ,单元分析 ,栅格提取, 代数 计算 等)
8、7、1邻域 分析
8、7、2密度 分析
8、7、3 3D 分 析(获取高程、通视分析)
8、7、4Tin 表面分析
8、7、5 Tin 生成 等高 线
8、8AE 创建 泰森 多边 形
8、9波段 计算 和影 像金字 塔
8、10分级 渲染
8、11拉伸

九. 编辑(IWorkspaceEdit 、IMultiuserWorkspaceEdi t)
9、1 Network dataset 分析
9、2如何创建一个无向网络
9、3线性 参考
9、3、1为什么使用线性参考
9、4什么是动态分段

十二 .安装 部署
12、2. 将 NetFramwork35sp1 ,ArcGIS Engine Runtime 一起打包




一、ArcGIS介绍
ArcGIS 软件 架构


ArcGIS 是 ESRI 在全面整合了 GIS 与数据库、软件工程、人工智能、网络技术及其它多方面的计算机主流
技术之后,成功地推出了代表 GIS 最高技术水平的全系列 GIS 产品。ArcGIS 是一个全面的,可伸缩的 GIS
平台,为用户构建一个完善的 GIS 系统提供完整的解决方案。ArcGIS 的基本体系能够让用户在任何需要的
地方部署 GIS 功能和业务逻辑,无论是在桌面、服务器、还是在野外:


桌面 GIS(ArcGIS Desktop)—ArcGIS 桌面 GIS 软件产品是用来编辑、设计、共享、管理和发布地理信息
和概念。ArcGIS 桌面可伸缩的产品结构,从 ArcReader,向上扩展到 ArcView、ArcEditor 和 ArcInfo。目
前 ArcInfo 被公认为是功能最强大的 GIS 产品。通过一系列的可选的软件扩展模块,ArcGIS Desktop 产品
的能力还可以进一步得到扩展。


嵌入式 GIS(Embedded GIS)—ArcGIS Engine 是一个完整的嵌入式 GIS 组件库和工具包,开发者能用它创
建一个新的、或扩展原有的可定制的桌面应用程序。使用 ArcGIS Engine,开发者能将 GIS 功能嵌入到已
有的应用程序中,如基于工业标准的产品以及一些商业应用,也可以创建自定义的应用程序,为组织机构
中的众多用户提供 GIS 功能。


服务器 GIS(Server GIS)—ArcGIS Server、ArcIMS 和 ArcSDE 用于创建和管理基于服务的 GIS 应用程序,
在大型机构和互联网上众多用户之间共享地理信息。ArcGIS Server 是一个中心应用服务器,它包含一个
可共享的 GIS 软件对象库,能在企业和 Web 计算框架中建立服务器端的 GIS 应用。ArcIMS 是通过开放的 I

nternet 协议发布地图、数据和元数据的可伸缩的网络地图服务器。 ArcSDE 是在各种关系型数据库管理系
统中管理

地理信息的高级空间数据服务器。


移动 GIS(Mobile GIS)— ArcPad,支持 GPS 的无线移动设备,越来越多地应用在野外数据采集和信息访
问中。ArcGIS 桌面和 ArcGIS Engine 可以运行在便携式电脑或平板电脑上,用户可以在野外进行数据采集、
分析和乃至制定决策。


ArcGIS Engine 介 绍


ArcGIS Engine 是一组完备的并且打包的嵌入式 GIS 组件库和工具库,开发人员可用来创建新的或扩展已
有的桌面应用程序。使用 ArcGIS Engine,开发人员可以将 GIS 功能嵌入到已有的应用软件中,如自定义
行业专用产品;或嵌入到商业生产应用软件中,如 Mirosoftf Word 和 Excel;还可以创建集中式自定义
应用软件,并将其发送给机构内的多个用户。


ArcGIS Engine 由两个产品组成:构建软件所用的开发工具包以及使已完成的应用程序能够运行的可再发
布的 Runtime(运行时环境)。 ArcGIS Engine 开发工具包是一个基于组件的软件开发产品,可用于构建
自定义 GIS 和制图应用软件。它并不是一个终端用户产品,而是软件开发人员的工 具包,适于为 Windows、
UNIX 或 Linux 用户构建基础制图和综合动态 GIS 应用软件。ArcGIS Engine Runtime 是一个使终端用户
软件能够运行的核心 ArcObjects 组件产品,并且将被安装在每一台运行 ArcGISEngine 应用程序的计算机
上。



?
?

ArcGIS Engine 是基于 COM 技术的可嵌入的组件库和工具包,ArcGIS Engine 可以帮助我们很轻松的构
建自定义应用程序.
使用 ArcGIS Engine,开发人员可以将 GIS 功能嵌入到已有的应用软件中,如自定义行业专用产品;
或嵌入到商业生产应用软件中,如 Mirosoftf Word 和 Excel;还可以创建集中式自定义应用软件,并
将其发送给机构内的多个用户。


ArcGIS Engine 由两个产品组成:
? 面向开发人员的软件开发包(ArcGIS Engin e Develop er kit)
? 面向最终用户的运行时(ArcGIS Engin e Run time)
ArcGIS Engine 开发工具包是一个基于组件的软件开发产品,可用于构建自定义 GIS 和制图应用软件。它
并不是一个终端用户产品,而是软件开发人员的工具包,支持四种开发环境(C++, COM, .NET,以及
Java),适于为 Windows、 UNIX 或 Linux 用户构建基础制图和综合动态 GIS 应用软件。
ArcGIS Engine Runtime 是一个使终端用户软件能够运行的核心 ArcObjects 组件产品,并且将被安装在
每一台运行 ArcGIS Engine 应用程序的计算机上。

ArcGIS Engine 的逻辑体系结构 :
◆ Ba se Se rvices
包含了 ArcEngine 中最核心的 ArcObjects 组件,几乎所有的 GIS 组件需要调用它们,如 Ge
ometry 和 Display 等。
◆ Data Acce ss
包含了访问矢量或栅格数据的 GeoDatabase 所有的

接口和类组件。
◆ Map Pre sentation
包含了 GIS 应用程序用于数据显示、数据符号化、要素标注和专题图制作等需要的接口和类
组件。


◆ Develper Components
包含了进行快速开发所需要的全部可视化控件,如 MapControl、PageLayoutControl、SceneControl、Glo
beControl、TOCControl、ToolbarControl、SymbologyControl 和 LicensenControl 控件等,除了这些,
该库还包括大量可以有 ToolbarControl 调用的内置 commands、tools、Menus,它们可以极大地简化二次
开发工作。
◆ Extensions


在图中我们可看出,ArcEngine 的开发体系是一条纵线,功能丰富,层次清晰。最上层的 Extensions 包含
了许多高级开发功能,如 GeoDatabase Update、空间分析、三维分析、网络分析、Schematics 逻辑示意图
以及数据互操作等。ArcEngine 标准版并不包含这些 ArcObjects 许可,他们只能作为扩展存在,需要特定
的 License 才能运行。


1、1ArcGIS Engine 中 的类 库


ArcGIS Engine 开发中,为了更好的管理这些 COM 对象,ESRI 将这些 COM 对象放在不同的组件库中,而他
们被物理的防盗 bin 目录下的 dll 中,而逻辑上被分散到不同的命名空间中


System
System 库是ArcGIS 架构中最底层的库。该库包含了暴露组成ArcGIS 的其它库所使用的服务的组件。
System 库中定义了许多接口,它们可以由开发者来实现。AoInitializer 对象在 System 中定义;所有开
发者必须使用该对象在使用Engine 功能的应用程序中初始化和uninitialize ArcGIS Engine。开发者不扩
展该库,但可以通过实现其中的接口来扩展ArcGIS系统。
SystemUI


SystemUI 库中包含了可在ArcGIS Engine 中扩展的用户界面组件的接口定义,包括 ICommand、ITool 和
IToolControl 接口。开发者使用这些接口来扩展UI 组件。该库所包含的对象是utility 对象,开发者可
用于简化某些用户界面的开发。开发者不扩展该库,但可以通过实现其中的接口来扩展ArcGIS 系统。
Geometry
Geometry 库处理存储在特征类(feature classes)或其它图形要素(graphical elements)中的特征的
geometry 或shape。大多数用户交互的基本几何对象有Point 、MultiPoint 、Polyline和Polygon 。除了
这些顶层的实体,还有作为Polylines 和Polygons 构建模块的几何体(geometries)。这些是组成几何体的
基元(primitives)。它们是Segments、Paths 和Rings。Polylines和Polygons 由形成一条Path 的依次相
连的Segments 组成。一个Segment 包含两个不同的点,
起点和终点,和一个定义从起点到终点的曲线的要素类型。这种segments 有 CircularArc、Line、
EllipticArc 和BezierCurve。所有的几何对象都可以有与它们顶点相关的Z、M 和IDs。基本的几何对象都
支持几何操作,如Buffer 和Clip。开

发者不可以扩展几何基元。GIS 中的实体是指现实世界中的特征;这
些现实世界中的特征的位置由具有空间参考的几何体来定义。投影和地理坐标系统的空间参考对象都包含
在Geometry 库中。开发者可以通过在空间参考间添加新的空间参考和投影来扩展空间参考系统。


Display
Display 库包含了用于GIS 数据显示的对象。除了负责实际图像输出的主要显示对象,该库中还包含了表
示颜色和符号的对象,这些颜色和符号用于控制显示上所绘制实体的属性。库中也包含了为用户在与显示
交互时提供可视化反馈的对象。开发者大都通过类似于Map 或PageLayout 对象提供的视图与显示交互。该
库的所有部分都可以被扩展,常被扩展的有符号、颜色和显示反馈(display feedbacks)。
Output
Output 库被用于创建图形输出到设备,如打印机、绘图仪和硬拷贝格式,如增强型图元文件 (enhanced
metafiles)和栅格影像格式(JPG、BMP 等)。开发者使用该库和ArcGIS 系统其它部分中的对象来创建图形
输出。通常这些是Display 和Carto 库中的对象。开发者可以扩展output 库用于定制的设备和输出格式 。
GeoDatabase
GeoDatabase 库提供了用于geodatabase 的编程API。Geodatabase 是一个构建在标准工业关系和对象数据

库技术基础上的地理数据储存库。库中的对象为ArcGIS 支持的所有数据源提供了统一的编程模型。
GeoDatabase 库定义了许多由架构中较高层次数据源提供者实现的接口。开发者可以扩展geodatabase 来
支持特殊的数据对象(Features、Classes 等)类型。此外,还可以使用PlugInDataSource 对象添加自定义
的矢量数据源。geodatabase 支持的native
数据类型不可以被扩展。


DataSourcesFile
DataSourcesFile 库包含用于基于文件数据源的GeoDatabase API 的实现。这些基于文件的数据源包括
shapefile、coverage、TIN、CAD、SDC、ArcGIS StreetMap?和VPF。开发者不能扩展DataSourcesFile 库。
DataSourcesGDB
DataSourcesGDB 库包含了用于数据库数据源的GeoDatabase API 的实现。这些数据源包括 Microsoft
Access 和SDE?软件支持的RDBMSs。开发者不能扩展DataSourcesGDB库。
DataSourceOleDB
DataSourcesOleDB 库包含用于Microsoft OLE DB 数据源的GeoDatabase API 的实现。该库只有在
Microsoft Windows 操作系统上才可以使用。这些数据源包括任何OLE DB 支持的数据提供者和文本文件工
作空间。开发者不能扩展DataSourcesOleDB库。
DataSourceRaster
DataSourcesRaster 库包含了用于Raster 数据源的GeoDatabase API 的实现。这些数据源包括 SDE 软件支
持的RDBMSs,和所有支持的RDO栅格文件格式。当需要支持新的栅格
格式时,开发者不扩展该库,而是扩展RDO。开发者不扩展DataSourcesRaste 库


GeoDatabaseDistributed
GeoDatabaseDistributed 库通过提供数据导入、导出geodatabase 的工具来支持到企业 geodatabase 的分
布式访问。开发者不扩展GeoDatabaseDistributed 库。


Carto
Carto 库支持地图的创建和显示;这些地图可以包含一幅地图或具有多幅地图和相关旁注的页中的数据。
PageLayout 对象是宿主一幅或多幅地图和相关旁注(指北针、图例、比例尺条等 )的容器。Map 对象是图层
的容器。Map 对象有操作地图中所有图层的属性:空间参考、地图比例尺等,还有操作地图图层的方法。
有多种不同类型的图层可以被加载到地图中。不同数据源通常有一个相关图层负责在地图上显示数据;矢
量特征由FeatureLayer 对象处理,栅格数据由 RasterLayer 对象处理,TIN 数据由TinLayer 对象处理等。
若需要,图层可以为它们的相关数据处理所有的绘制操作。但更常见的是图层拥有一个相关的Renderer 对
象。Renderer 对象的属性控制数据在地图中怎样显示。Renderers 一般使用 Display 库中的symbols 进行
实际绘图;renderer 只是匹配指定的符号与要绘制的实体的属性。一个Map 和一个PageLayout 可以包含
要素(elements)。要素利用几何体来定义它在地图或页面上的位置,以及控制要素显示的行为。有用于基
本形状、文本标注、复杂旁注等的要素。Carto 库也包含对地图注记和动态标注的支持。
Location
Location 库包含支持地理编码和与route 事件一起工作的对象。可通过full 控件的finegrained对象访问
地理编码功能,或GeocodeServer 对象提供了一个简化的API。开发者可以创建他们自己的地理编码对象 。
线性参考功能提供了添加事件到线性特征的对象,并使用多种绘制方法渲染这些事件。开发者可以扩展线
性参考功能。
NetworkAnalysis
NetworkAnalysis 库提供的对象在网络加载到geodatabase 中时,使用网络数据和对象populating a
geodatabase 来分析网络。开发者可以扩展该库来支持定制的网络跟踪。该库是用于utility 网络的——
gas lines、electricity supply lines 等。

Controls


开发者使用Controls 库来构建或扩展具有ArcGIS 功能的应用程序。ArcGIS Controls 通过封装
ArcObjects 和提供一个coarser-grained API,简化了开发过程。尽管控件封装了fine grained ArcObjects,
但它们并不限制访问这些ArcObjects。MapControl 和PageLayoutControl分别封装了Carto 库中的Map 和
PageLayout 对象。ReaderControl 封装了Map 和PageLayout对象,并在使用该控件时提供了简化的 API。
如果地图出版商拥有授权许可,那么开发者可
以访问Map 和PageLayout 控件的类似方式访问内部对象。该库也包含实现内容列表的 TOCControl 和宿主
与一个合适控件一起工作的命

令和工具的ToolbarControl


GeoAnalyst
GeoAnalyst 库包含支持核心空间分析功能的对象。这些功能在ArcGIS Spatial Analyst和ArcGIS 3D
Analyst?库中使用。开发者可以通过创建一个新的栅格操作类型来扩展该库。要求有ArcGIS Spatial
Analyst 或3D Analyst 许可才能使用该库中的对象。
3DAnalyst
3DAnalyst 库包含在三维场景中使用的对象,它们的工作方式类似于Carto 库中包含的对象在二维地图中
工作。Scene 对象是库中的主要对象之一,因为它与Map 对象类似,是数据的容器。Camera 和Target 对
象根据特征相对于观察者的位置,指定场景的视图。一个场景(scene)包含一个或多个图层;这些图层指定
了场景中的数据和数据怎样绘制。
3DAnalyst 库拥有一个开发控件和一组和该控件协同工作的命令和工具。该控件可以与Controls 库中的对
象联合使用。除了创建命令和工具,开发者对该库的扩展较少。使用该库中的对象需要3D Analyst 许可。
GlobeCore
GlobeCore 库包含与globe 数据一起工作的对象,工作方式类似于Carto 库中包含的对象在二维地图中工
作。Globe 对象是库中的主要对象之一,因为它与Map 对象类似,是数据的容器。GlobeCamera 对象根据
globe 相对于观察者的位置,指定了 Globe 视图。Globe 可以有一个或多个图层;这些图层指定了Globe 上
的数据和数据怎样绘制。


介绍完这些,让我们有个感性上的认识,在以后找某个对象的时候,知道去哪个 dll 中找。



1、2 和ArcGIS

Engine开发相关的C#知识




1.2.1接口 编程


使用 ArcGIS Engine,也就意味着使用里面的接口,那么什么是接口呢?在面向对象的编程中,我们都会
接触到这个玩意儿,我们知道面向对象有三大特性 封装,继承,多态,相信很多人在学习多态的时候,
会接触接口。

接口可以用这样一句话来描述“接口就是包含一系列不被实现的方法.而把这些方法的实现交给继承它的
类.”,这句话看起来很晦涩,没关系,我们通过下面一个例子说明 我定义了一个接口 IPeople


using System;
using System.Collections.Generic;
using System.Text;


namespace InterfaceTest
{
interface IPeople
{
void gender();
}
}


这个接口里面有一个性别的方法,这个只对方法进行了定义,而方法内却没有内容,也就是说,通过这个
接口的这个 gender 方法,我们不能知道它到底干什么,但是要知道这个 gender 到底是干什么用的,那么
就要看实现了这个方法的类。同理我定义两个类,分别实现这个接口。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace InterfaceTest
{
class Boy:IPeople
{
public void gender()
{

Console.WriteLine("I’m a boy.");
}

}

}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace InterfaceTest
{
class Girl:IPeople
{
public void gender()
{
Console.WriteLine("I’m a girl.");



}

}
}


通过上面的两个类,我们就很清楚的看到这个方法的作用了,我们也可以看到一个接口可以被多个类实现。
我们运行一下这个,看一下效果
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace InterfaceTest
{
class Program
{
static void Main(string[] args)
{
IPeople Person; // 声明接口变量

Person = new Boy(); // 实例化,接口变量中存放对象的引用
Person.gender(); // 这个调用的是 Boy 中的 gender 方法
Person = new Girl(); // 实例化,接口变量中存放对象的引用
Person.gender(); // 这个调用的是 Gril 中的 gender 方法
Console.ReadLine();



}

}
}


运行结果如下:


1、3C#接 口的 例子


1、3、1快速 掌握 OMD


我们已经知道使用 ArcGIS Engine 开发,也就意味着我们要和接口打交道,ArcGIS Engine 中提供的接口
和类加起来估计上万,但是用过 ArcGIS Engine 的人,知道这个数字不为过。ArcGIS Engine 为了帮助我
们方便的使用这些,将这些分散在不同的类库中,为了便于我们阅读,ArcGIS Engine 提供了一系列的对
象模型图,也就是 OMD (Object model diagrams) 对象模型图表。
下面图示中,便是贯穿本节的对象模型图的钥匙。


这些符号是基于 UML 画图工具创建的,UML 符号是面向对象分析和设计的工业图样标准。
对象模型图中提供的信息非常多,是对象浏览器中信息的重要补充。Visual Basic,或者其它的开发环境,
都会列出所有的类和成员,但不会指明这些类之间的关系。所以,对象模型图是非常有利于读者对 ArcInfo
组件的理解的!
本书使用 UML 来描述 ArcInfo 组件,即 ArcObjects,并描述你能够创建的数据模型。
以下详细说明。


1. 类和 对 象
在 UML 图中有三种类型的类:抽象类(abstract class)、组件类(CO class)与普通类(instantiable
class)。
抽象类:不能创建或实例化,从来没有一个抽象类的实例用于定义子类的公共接口,创建实例的任务由其
子类完成。子类继承其定义的接口。 OMD 符号为:二维的内部有阴影的矩形。
普通类:不能创建,从别的对象获得实例。 OMD 符号为:3D 矩形内部没有阴影。
组件类:可以直接创建实例的类,在 C#中,用 New 关键字。 OMD 符号为:带阴影的 3D 矩形符号。
2. 关联

在抽象类、可创建类和可实例化类之间,有几种存在的关联(或称关系)。


联系(associa

tion)便描述了类之间的关联。在两端的类中可以定义多重性( Multipli city)关联。


在这张图上,一个业主能有拥有一块或多块宗地;同样地,一块宗地可以被一个
或多个业主所共有。
多重性关联就是限制对象类与其它对象关联的数目关系。以下是用于多重性关联
的符号:
1 —— 一个并 且只有一个,这种多样性是可选的;如果不标明,则默认为“1”
0..1 —— 零个 或一个
M..N —— 从 M 到 N(正整数)
*或者 0… * —— 从零到任意正整数
1… * —— 从一到任意正整数
多个联系


在这张图上,我们可以得知有不
类继承(type inheritance)定义了专门的类,它们拥有超类的属性和方法,并且同时也有自身的属性和方
法。


上图说明 primary line 和 secondary line 是 line 的一种类型。
实例化(Instanti ation)指定一个类的对象有这样的方法,它能够创建另外一个类的对象。


pole 对象有一个方法能够创建 transformer 对象。
聚合(Aggregati on)是一种不对称的关联方式,在这种方式下一个类的对象被认为是一个 “整体”,而另一
个类的对象被认为是“部件”。


一个 transformer bank 正好有 3 个 transformer 。在这个图中 transformer 能和一个 transformer bank
相关联,但当 transformer bank 移除以后,transformer 依然能够存在。


组成(Com positi on)是一种更为强壮的聚合方式,此种方式下,“整体”对象控制着“部分”对象的生存时间。


一个 Pole 包含一个或多个 Crossarm。在这个图中当 pole 被移除后,Crossarm 就不能再使用了。因为 Pole
控制着 Crossarm 的生存时间。
在 OMD 图中,我们不仅仅能看到类之间的相互关系,还可以得到属性的一些信息,如下图:


属性和方法:
属性:哑铃状的图标,Read(左侧的实心哑铃)和 write(右侧的实心哑铃)
属性除了我们常说的类型,还有一种属性,这个属性本身就是一个对象,符号,空心的哑铃
方法:指向左侧的箭头。

ArcEngline 组件库的每一个组件中定义有不同的类,类下面定义了不同接口,接口中包含不同的属性和方
法。类之间有类型继承(Typelnheritance)关系,接口之间有互相调用(Query lnterface) 及相互继承
(Interfacelnheritance)关系。


1.1 类与对象在面向对象编程中,类和对象是两个非常重要的概念,可以这么说类就是创建对象的蓝本 ,而
对象是指具有属性和动作的实体,它封装了一个客观实体的属性与行为。ArcObjc ets 中有三类 class,分别是
抽象类(AbstractClass)、组件类(CoClass)和普通类(Class)。抽象类的主要目的是为它的子类定义公共
接口,一个抽象类将把它的部分或全

部实现延迟到子类中,因此,一个抽象类不能被实例化。一个组件类
对象可以被直接创建,普通类对象虽然不能直接创建,但它可以可以作为其它类的一个属性或者从其它类
的实例化来创建。


1.2 接口和类接口定义了一组方法和属性,在 ArcObjects 中接口名称都以”I”开始,如 IMap, Ilayer 等。类
实现了接口中的方法。一个类可以有多个接口,如 FeatureLayerClass 类有 IFeatureLayer,IFeatureSelection
等不同接口,而一个接口也可被多个类所拥有,如 CadFeatureLayer 类和 FeatureLayer 类都有 IFeatureLayer
接口。接口定义了能做什么,而定义了该怎么做(The interfacedefines what an object can do, and the class
defines how it is done.79 页 Explroing ArcObjects V9.0),在 AO 开发的时候,和对象间的通信是通过接口完
成的,而不是我们在一些其他面向对象语言如(Java)中和对象的通信是通过对象完成的.


1.3 接口查询(Query Interface) 一个类可以有多个接口,声明了接口变量并且指向一个对象的时候,这个变
量只能使用该接口内的方法和属性,而不能 访问其他接口中的方法和属性,如: Dim pMap as IMap Set pMap
= New Map p Map.Clear ‘这里会产生错误此时的 pMap 只能使用 IMap 接口中定义的方法和属性,比如获取
图层的个数,添加图层等,但是不能清空视图上的内容(因为这个方法是在 IActiveView 中定义的)
QueryInterface(QI)很方便的让我们在一个类的不同接口间进行切换:


Dim pView as IActiveView set pView= pMap ‘QI 现在 mView 就可以使用 IActiveView 中定义的方法了.


1.4 类类型继承类型继承是指类之间的接口类型的继承,而不是继承其实现。继承过来的接口只是名称相
同,具体的实现则不同。比如 ShpfileWorkspaceFactry 和 AccessWorkspaceFactry 都继承 WorkspaceFactry ,
而他们的打开(Op enFromFile)方法却不一样,ShpfileWorkspaceFactry 的(Op enFromFile)方法需要一个
文件目录位置作为参数,而 AccessWorkspaceFactry 的(Op enFromFile)方法需要一个数据库(mdb)位置
作为参数。1.5 接口继承如 ImapFrame 接口和 IMapSurroundFrame 接口继承于 IFrameElement 接口,则父类
接口 IFrameElement 所具有的方法和属性对派生接口 ImapFrame 和 IMapSurroundFrame 都有效。

1、4快速 理解 Q I


C#+QI 的例 子


COM 中,和我们打交道的是接口,也就是说类对我们是隐形的,那么我们要做开发,要使用这些功能,我
们只能通过接口,通过接口暴露出来的方法,COM 是一种服务器端/客户端架构,服务器端定义了操作的方
法,客户端通过接口调用这些方法。下面的这幅图很能说明 COM 的结构:


言归正传,说这篇博文的主题 QI,还记得上

一篇我强调的,一个接口可以被多个类实现,而 QI 要解决的
就是一个类实现多个接口的问题。在 COM 中,接口定义了方法,类实现了接口中定义的方法,而一个接口
只能使用自己内部定义的方法,而不能越界,就好比一个班级一样,这个班级内有班长,有学习委员,有
体育委员,每位干部各司其职,每一位干部负责自己职权范围之内的事情,各位干部相互协作,解决班级
内的事情,这班级内的每一位干部就相当于一个接口,而这个班级就相当于实现了这些接口的类。当这个
班级的一些事情需要班长处理的时候,我们就执行班长这个接口中定义的方法,当需要学习委员处理的话,
我们再将执行权交给学习委员这个接口,这也就是接口之间的互相访问(Query Interface),通过这个我
们大体上对 QI 有了感性上的认识,下面我们通过实例演示一下。
我定义了两个接口
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace QITest
{
interface IFavoriteFood
{
void Food();
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace QITest
{

}

interface IVoice
{
void Voice();
}

然后定义了一个Cat的类实现这里面的方法
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace QITest
{
class Cat:IFavoriteFood ,IVoice
{
public void Food()
{
Console.WriteLine("我喜欢的食物是老鼠.");
}
public void Voice()
{
Console.WriteLine("喵,喵,喵...");



}

}

}

这个Cat类的功能就是实现两个接口的方法,猫最喜欢的事物是老鼠,而他的声音是“喵,喵,
喵”。
运行下
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace QITest
{
class Prog ram
{
static void Main(string[] args)
{
IVoice pVoice = new Cat();
pVoice.Voice();//只能调用IVoice中定义的方法
// pVoice.Food();这个就会报错,因为 IVoice 接口中没有这个方法的定义
IFavoriteFood pFavoriteFood = pVoice as IFavoriteFood;
pFavoriteFood.Food();//只能调用IFavoriteFood定义的方法
Console.ReadLine();



}

}

}

效果如下:


三. 使用 控件 创建 第一个桌面应用 程序



1)

建 一 个 Windows 窗 体应 用 程 序(文件--新 建--项目--Windos 窗体应用程序)


2)在 点 了确定之后 ,在 VS 的工具箱中 找到到和 ArcEngine 相 关 的 控件


其中,AxMapControl 就是 Map 地图控件,AxPageLayouControl 是布局地图控件,
AxTOCControl 是目录控件,AxToolbarControl 是 GIS 工具栏控件,
AxSceneControl 是 Scene 三维场景控件,axGlobeControl 是 Globe 控件,
AxLicenseControl

是许可控件,AxSymbologyControl 是符号选择器控件,
AxArcReaderControl 是 ArcReader 控件,AxArcReaderGlobeControl 是
ArcReaderGlobe 控件。AxLicenseControl 是许可控件,一般 GIS 系统中都必须
添加,否则无法使用。将刚才的窗体的名称改为 Engine
3)然 后 添 加 Toc, Map, Toolbar 控 件 。许可控件是首 选的,否则无法使用


添加 完 这几个控件 后,VS 会自动为我们添加一些 引用


4)添 加 地 图文档(Map 控 件-右键-属 性)


5)Toolbar 控 件 和 Toc 控件 与 Map 控 件的关联(设置 Bu ddy 属性)


6)在 Toolbar 中 进 行 设置 ( Toolbar 控 件-右键-属性-Itmes 选 项)


7)添 加 工 具命令

在 Toolbar control 上右键—属性在 items 选项卡中添 加几个工具命令


8)运 行 我们的应用 程序,发现下面的错误


出现这个问题的原因是因为 ArcGIS 10 发生了变化,将下面的语句添加到使用
AO 对象的前面:


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


如我放在 Main 函数中


利用刚才添加的打开文档的命令打开一个新的文档


也可利用上面的放大,缩小工具进行简单的操作了。


在上面,当我们将这些空间拖到窗体中的时候,会自动加载一些 dll,我们知道
ArcGIS Engine 编程,也就意味着和 COM 对象接触。


2、1代 码加 载 Mxd 文档


用代码添加 Mxd 文档,用到 AxMapControl.LoadMxFile(sFilePath),我们只要将 Mxd 文档的路
径传给这个方法即可。我们添加一个按钮:


在这个按钮的单击事件中填写如下代码:


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);


控件的 LoadMxFile 是用来加载地图文档的


我们将刚才写的代码封装成一个函数


public string OpenMxd()
{
string MxdPath = "";

OpenFileDialog OpenMXD = new OpenFileDialog();


OpenMXD.Title = "打开地图";


OpenMXD.InitialDirectory = "E:";


OpenMXD.Filter = "Map Documents (*.mxd)|*.mxd";


if (OpenMXD.ShowDialog() == DialogResult.OK)
{


MxdPath = OpenMXD.FileName;


}



}

return MxdPath;


2、2添加 Shape 文 件


AxMapControl 还包含下面三个方法用来添加不同类型的数据


这些方法的使用和上面的相似,方法中的参数可能不同,对于 AddShapeFile 来说,它需要两个参数,第一
个参数是 shp 文件名所在的目录,第二个是文件名,因为打开 shp 文件要两个参数,所以构造一个数组,
用来返回相应的参数


代码如下:


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 = https://www.doczj.com/doc/f71287663.html,stIndexOf("\\");


string FilePath = ShapPath.Substring(0,Position);


string ShpName = ShapPath.Substring(Position+1);


ShpFile[0] = FilePath;


ShpFile[1] = ShpName;


}



}

return ShpFile;


2、3庖丁 解牛 识控 件


ArcGIS Engine 中提供了很多的控件,这些控件和 ArcMap 中的一些东西有对应关系的:



ArcGIS Engine 中的 MapControl 控件和 Pag eLayoutControl 控件分别对应于 ArcMap 中的数据
视图和布局视图,MapControl 控件主要用于空间数据的显示和分析,它封装了地图对象,
而 PageLayoutControl 控件是用于地图的修饰和整理,可以用来生成专题图等,它封装了
PageLayout 对象。


TOCControl 控件 和 ToolbarControl 控件分别对应 ArcMap 中的 Table of Contents 控件和工具条
控件,这两个控件都有一个 buddy 属性,这两个控件需要和一个伙伴空间协同工作,伙伴
控件可以是 MapControl,Pag eLayoutContro,SceneControl 或者 globeControl 控件。


IMap Documen t p MapD ocum ent = ne w MapDo cum entC lass();


if ( pMapDoc ume nt.get_I sMa pDocume nt( path))
{
pMa pDocume nt. Open(path, null) ;
IMa p pMap;
for (int i = 0; i < = p MapDocum ent .MapCou nt - 1; i ++)
{
pM ap = pMapD ocu ment.get _Ma p(i);
Co nso le.Writ eLi ne(pMap. Nam e);
IE num Layer p Enu mLayer = pM ap.get_ Lay ers(n ull, tr ue);
pE num Layer.R ese t();
IL aye r pLaye r = pEnumLa yer .Next() ;
wh ile (pLaye r ! = n ull )
{
C ons ole.Wri teL ine(pLay er. Name);



}

p Lay er = pE num Layer.Ne xt( );

}

}


2、4第一 个控 件 MapControl


MapControl 对应于 ArcMap 中的数据视图,它封装了 Map 对象,并提供了额外的属性,方法,事件等。在
ArcGIS Engine 的帮助文件中,我们可以看到 MapControl 主要实现了如下接口:


在前面的例子中,我们已经看到如何使用 MapControl 加载 Mxd 文档和 Shp 文件等。下面
我们通过实现鹰眼图这个功能来进一步学习 MapControl 控件。在实现鹰眼图之前,我们需
要接口有更深入的了解。


2、5变主动为被动-出接口(OutBound interface)


COM 编程类似客户端和服务器端的两层结构,COM 所建立的是一个软件模块与另一个软
件模块之间的链接, 当这种链接建立之后, 模块之间就可以通过被称之为 Interface“接口 ”
的机制来进行通信。在绝大部分情况下, 客户

应用程序与组件的通信过程是单向的, 客户创
建组件对象, 然后客户通过接口调用对象所提供的功能, 在适当的时候再把对象释放掉。在

这种交互过程中, 客户总是主动的, 而组件总是处于被动状态, 通过自身暴露给客户的接
口监听客户的请求, 一旦接收到客户的请求便做出反应,这些反应的“幕后“,也就是代码
是被屏蔽掉的,我们是看不到这些接口内的方法是如何实现的。这样的接口称为入接口
InBound Interface,但是对于一个全面交互过程来说, 这样的单向通信往往是不能满足实
际的需要, 组件对象也要主动与客户进行通信, 因此, 与入接口相对应, 对象也可以提供出
接口 OutBound interface,对象通过这些出接口与客户进行通信。之所以把这些接口称为
出接口, 其原因在于这些接口并不由 COM 服务器端的对象实现, 而是由客户程序自己来
实现, 客户实现这些接口, 服务器端调用此接口的成员函数, 即调用了客户自定义的函数,
这时组件对象变成了客户端的客户。也就是说出接口的实现是由我们自己实现,而被服务器
调用,这样的接口,我们往往称之为事件接口,这些接口里面定义了一些如 OnMouseUp,
OnMouseMove 等函数,当相应事件发生的时候,由服务器去执行这个事件里面的内容。


2、6鹰眼图的实现


鹰眼图的实现用到控件如下::



控件名称 控件类型 备注 axMapControl1 主图 axMapControl2 鸟瞰图 axToolbarControl1 axTOCControl1

分析:鹰眼图的操作主要由以下几个动作,当在一个控件中移动一幅图的时候另一控件中的
图也发生变化,当在主控件中重新加载一幅图的时候,另外一个控件的图也发生相应的变化,
同时我们在鸟瞰的控件中加入一红色边框,注意这个其实是一个面,只是填充的颜色是透明
的而已。通过分析我们知道,我们要添加两个 MapControl 控件,名字分别是 axMapControl1
和 axMapControl2,其中 axMapControl1 为主图,而 axMapControl1 为鸟瞰图。


对于名称为 axMapControl1 的 MapControl 控件,只需要在 axMapControl1 的 OnExtentUpdated
和 OnMapReplaced 中分别添加以下代码:


private void axMapControl1_OnExtentUpdated(object sender,
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);


private void axMapControl1_OnMapReplaced(object sender,
IMapControlEvents2_OnMapReplacedEvent e)
{


if (https://www.doczj.com/doc/f71287663.html,yerCount > 0)
{
axMapControl2.Map = new MapClass();


for (int i = 0; i <= https://www.doczj.com/doc/f71287663.html,yerCount - 1; i++)
{
axMapControl2.AddLayer(axMapControl1.get_Layer(i));

}
axMapControl2.Extent = axMapControl1.Extent;


axMapControl2.Refresh();



}

}


对于名称为 axMapControl2 的 MapControl 控件,只需要在 axMapControl2 的 OnMouseMove 和 OnMouseDown
中分别添加以下代码:


private void axMapControl2_OnMouseMove(object sender, IMapControlEvents2_OnMouseMoveEvent
e)
{
if (e.button == 1)
{
IPoint pPoint = new PointClass();


pPoint.PutCoords(e.mapX, e.mapY);


axMapControl1.CenterAt(pPoint);



null, null);

axMapControl1.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeography,



}

}



e)

private void axMapControl2_OnMouseDown(object sender, IMapControlEvents2_OnMouseDownEvent
{
if (https://www.doczj.com/doc/f71287663.html,yerCount > 0)
{
if (e.button == 1)
{
IPoint pPoint = new PointClass();


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);



}

}

}


运行后的效果如下:


2、7 TOCContro 控 件


TOCControl 控件使用的是用伙伴控件中的数据地图,它控制图层是否在伙伴控件空显示以及
和伙伴控件在符号上保持一致,TOCControl 为用户提供了一个交互式的环境,如果
TOCControl 控件的伙伴控件是 MapControl 控件,当我们将 TOCControl 控件中图层删掉是,
MapControl 控件中相应的图层也会被删掉。

2、8显示属性表的信息



我们知道 ArcMap 中的 Table of Contents 有很多功能,如下图:


而 ArcGIS Engine 提供的 TOCControl 控件几乎没有提供,那么这些都是需要自己开发的,在
这里我做一个显示属性表的功能。


分析:要显示某一个图层的属性表,首先要将这个图层选中,然后在另外一个 Form 中将选
中的这个图层的属性信息进行显示。


添加一个上下文菜单,添加一个新的 Form 窗体,在这个新的窗体上添加 GridView 控件,并
在 TOCControl 控件的 OnMouseDown 事件下添加如下代码(pGlobalFeatureLayer 是我定义的一个全局变量):


private void axTOCControl1_OnMouseDown(object sender,
ESRI.ArcGIS.Controls.ITOCControlEvents_OnMouseDownEvent e)
{


if (https://www.doczj.com/doc/f71287663.html,yerCount > 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
pGlobalFeatureLayer, ref pOther, ref pIndex);
}


if (e.button == 2)
{
context.Show(axTOCControl1, e.x, e.y);
}


}


在上下文菜单的打开属性表的 Click 事件中添加如下代码:


private void 打开属性表ToolStripMenuItem_Click(object sender, EventArgs e)
{
FormTable Ft = new FormTable(pGlobalFeatureLayer as IFeatureLayer);


Ft.Show();


}


在新的窗体中添加一个将属性表显示到 GridView 控件中的函数,如下:


public void Itable2Dtable()
{


IFields pFields;
pFields = pFeatureLayer.FeatureClass.Fields;


dtGridView.ColumnCount = pFields.FieldCount;

for (int i = 0; i < pFields.FieldCount;i++ )
{


string fldName = pFields.get_Field(i).Name;
dtGridView.Columns[i].Name = fldName;


dtGridView.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));
}
dtGridView.Rows.Add(fldValue);
pFeature = pFeatureCursor.NextFeature();


}


}


运行后,效果如下:


2、9命令 和工 具的 宿主控 件 ToolBarControl 控 件


在 ToolBarControl 控件中,我们通过 ToolBarControl 控件的属性页面添加了一些如打开文档,
平移,放大等功能,在 ArcGIS Eng ine 中我们将宿主在 ToolBar

Control 控件中的内容分为三类
“命令,工具,工具控件“


命令,就是当用户单击时所产生的操作,比如说,我们要打开一个地图文档,我们只需要在
ToolBarControl 控件上添加打开地图文档这个操作,然后用鼠标点击。


工具,存在着交互这个操作。当我们在 ToolBarControl 控件上使用一个工具的时候,我们需
要通过两步操作:(1)单击这个工具,(2)使用这个工具更相应的控件做交互操作。


如果我们点击了平移这个操作,那么这个时候我们还要用鼠标和地图进行平移等交互,那和
谁交互呢,我们知道 ToolBarControl 有一个 buddy 属,这个就体现了在 budy 属性上。
ToolbarControl 会将伙伴控件的 CurrentTool 属性设置为我们用鼠标点击的工具,然后伙伴控
件就等着和我们的工具交互。


工具控件,这通常是用户界面组件,如 ToolBarControl 控件上的列表框和组合框。


其实在 ToolBarControl 控件中还可以宿主工具条菜单(ToolbarMenu),工具条菜单表示单击
命令项的一个垂直列表。用户必须选择工具条菜单上的一个命令项,或单击工具条菜单之外
的地方使其消失。工具条菜单只能驻留命令项(不允许驻留工具或者工具控件)


2、10命令和工具


在 ArcGIS Eng ine 中,命令是实现了 ICommand 接口,在 ArcGIS Eng in 的开发帮助中,我们可
以看到 ICommand 接口以下成员:


当用户单击这个命令时会导致 ICommand.OnClick 方法 被调 用 ,并 执行 某种 操作。


要将 一个 命令宿主到 ToolBarControl 控 件上 ,有 以下 三 种方 法:



1.

使用 UID



2.

使用 progID



3.

使用 ICommand


UID pUID = new UIDClass();


pUID.Value = "esriControls.ControlsUndoCommand";


axToolbarControl1.AddItem(pUID, -1, 0, false, -1,
esriCommandStyles.esriCommandStyleIconOnly);


axEditorToolbar.AddItem("esriControls.ControlsUndoCommand", 0, -1, true, 0,
esriCommandStyles.esriCommandStyleIconOnly);


ICommand pUndo = new ControlsUndoCommandClass();


axEditorToolbar.AddItem(pUndo, 0, -1, false, 0, esriCommandStyles.esriCommandStyleIconOnly);


ICommand 接口 是 可以 被扩 展的 ,也 就是说这个接口对我们 是开放 的, 只要我 们将
ICommand 接口 中 成员 实现 ,因 为这 个格式是固定的,Esri 提供 了相应的模板


我们知道宿主在 ToolBa rControl 上的 命令操作的对象是 ToolBa rControl 的伙 伴控件 ,但
是, 这个 命令怎么和 这个伙 伴控件 联系 起来了 ,注意到 ICommand 接 口中 有一个
ICommand.OnCreate 方法 ,这 个方 法有 一个 参数 hook。


[C #]
p u b l i c vo id O n C r e a t e (
object ho ok
) ;


这个 hook 是 一个 object 对 象。也就是 说这儿命令和

那个控件协作 ,要看这个 hook 传入 的
是那 种控 件。

当命令对象宿主到 ToolBarControl 控件上后就会立即调用 ICommand.OnCreate 方法,同时会
将 ToolBarControl 控件传递给 hook 这个参数,以便命令能和 ToolBarControl 控件的伙伴控件
协作。一般要在这个方法里面要测试这个 hook 是不是有效,也就是说这个命能不能和这个
hook 协作,要看这个命令支不支持这样的操作,比如说我们要打开一个地图文档,我们知
道打开地图文档这个命令是可以和 MapControl,Pag eLayoutControl 控件协作的,如果我们传
进去的是 TOCContro 控件,那么这个命令就会失效,这些话看起来很费解,我们通过一个代
码来好好体会这些话。


我们 自己 定义一个打 开地图 文档的 命令


利用 Esri 提 供的 命 令模 板


选择 和命 令对象协作 的控件


using System;
using System.Drawing;
using System.Runtime.InteropServices;
using ESRI.ArcGIS.ADF.BaseClasses;
using ESRI.ArcGIS.ADF.CATIDs;
using ESRI.ArcGIS.Controls;
using ESRI.ArcGIS.Carto;
using System.Windows.Forms;


namespace EngineApplication
{
///


/// Summary description for OpenMxdCommand.
///

[Guid("c142fea5-2e8e-4f68-95e1-9cad4a6a290e")]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("CalculateContourTask.OpenMxdCommand")]
public sealed class OpenMxdCommand : BaseCommand
{
#region COM Registration Function(s)
[ComRegisterFunction()]
[ComVisible(false)]
static void RegisterFunction(Type registerType)

{

// Required for ArcGIS Component Category Registrar support
ArcGISCategoryRegistration(registerType);



}

//
// TODO: Add any COM registration code here
//


[ComUnregisterFunction()]
[ComVisible(false)]
static void UnregisterFunction(Type registerType)
{
// Required for ArcGIS Component Category Registrar support
ArcGISCategoryUnregistration(registerType);



}

//
// TODO: Add any COM unregistration code here
//


#region ArcGIS Component Category Registrar generated code
///
/// Required method for ArcGIS Component Category registration -
/// Do not modify the contents of this method with the code editor.
///

private static void ArcGISCategoryRegistration(Type registerType)
{
string regKey = string.Format("HKEY_CLASSES_ROOT\\CLSID\\{{{0}}}",
registerType.GUID);
ControlsCommands.Register(regKey);


}
///
/// Required method for ArcGIS Component Category unregistration -
/// Do not modify the contents of this method with the code editor.
///

private static void ArcGISCategoryUnregistration(Type registerType)
{
string regKey = string.Format("HKEY_CLASSES_ROOT\\CLSID\\{{{0}}}",
registerType.GUID);
ControlsCommands.Unregister(regKey);


}


#endregion
#endregion


IMapControl2 pMapControl

;


public OpenMxdCommand()
{
//
// TODO: Define values for the public properties
//
base.m_category = "打开地图文档"; //localizable text
base.m_caption = "打开地图文档"; //localizable text
base.m_message = "打开地图文档"; //localizable text
base.m_toolTip = "打开地图文档"; //localizable text
base.m_name = "打开地图文档"; //unique id, non-localizable (e.g.
"MyCategory_MyCommand")



try
{
}

//
// TODO: change bitmap name if necessary
//
string bitmapResourceName = GetType().Name + ".bmp";
base.m_bitmap = new Bitmap(GetType(), bitmapResourceName);

}

catch (Exception ex)
{
System.Diagnostics.Trace.WriteLine(ex.Message, "Invalid Bitmap");
}


#region Overridden Class Methods


///


/// Occurs when this command is created
///

/// Instance of the application
public override void OnCreate(object hook)
{
if (hook == null)
return;
//在这里对hook进行判断


if (hook is IToolbarControl)



{
}

IToolbarControl pToolBar= hook as IToolbarControl ;
pMapControl = pToolBar.Buddy as IMapControl2;

else if(hook is IMapControl2 )
{
pMapControl = hook as IMapControl2;
}



}

// TODO: Add other initialization code


///
/// Occurs when this command is clicked
///

public override void OnClick()
{
// TODO: Add OpenMxdCommand.OnClick implementation


//launch a new OpenFile dialog
OpenFileDialog pOpenFileDialog = new OpenFileDialog();
pOpenFileDialog.Filter = "Map Documents (*.mxd)|*.mxd";
pOpenFileDialog.Multiselect = false;
pOpenFileDialog.Title = "Open Map Document";
if (pOpenFileDialog.ShowDialog() == DialogResult.OK)
{
string docName = pOpenFileDialog.FileName;


IMapDocument pMapDoc = new MapDocumentClass();
if (pMapDoc.get_IsPresent(docName)
&& !pMapDoc.get_IsPasswordProtected(docName))
{


pMapControl.LoadMxFile(pOpenFileDialog.FileName, null, null);


// set the first map as the active view

pMapControl.ActiveView.Refresh();


pMapDoc.Close();



}

}

}



}

}

#endregion


通过 下面 两句将我们 自定义 的打开 地图 文档的 命令宿主到 ToolBarControl 上


OpenMxdCommand pMxdCommand = new OpenMxdCommand();
axToolbarControl1.AddItem(pMxdCommand, -1, 0, false, -1,
esriCommandStyles.esriCommandStyleIconOnly);


效果如下:

我们可以对上述代 码添加 断点 ,发 现当程 序执行到 axToolbarControl1.AddItem(pMxdCommand, -1, 0,
false, -1, esriCommandStyles.esriCommandStyleIconOnly);的时候,OnCreate 函数被执行,进而对 hook
参数判断,通过进一步跟踪,发现程序执行到


if (hook is IToolbarControl)



{
}

IToolbarControl pToolBar= hook as IToolbarControl ;
pMapControl = pToolBar.Buddy as IMapControl2;


说明程序将 ToolbarControl 控件传入进去。



而工 具是 实现了 Itool 和 ICommand 这两 个接 口, 从 ITool 的接 口成 员中 我们 就不难看出
工具 和命 令的区别:


ITool 接口的成员几乎都是和交互相关的一些事件.


上述我们都是将命令或者工具宿主到了 ToolBarControl 控件上,能不能脱离 ToolBarControl 控件呢?答
案是可以的。

2、11脱离 ToolBarControl 控件 的命 令和 工具


我们在 Form 中添加 MenueStrip 控件,并添加以下几个功能,然后分别写入相应的代码


private void 文件ToolStripMenuItem_Click(object sender, EventArgs e)
{
ICommand pMxd = new ControlsOpenDocCommandClass();


pMxd.OnCreate(axMapControl1.Object);



}

pMxd.OnClick();


private void 查询ToolStripMenuItem_Click(object sender, EventArgs e)
{
ICommand pAddData = new ControlsAddDataCommandClass();


pAddData.OnCreate(axMapControl1.Object);



}

pAddData.OnClick();


private void 空间分析ToolStripMenuItem_Click(object sender, EventArgs e)
{
ICommand pZoomIn = new ControlsMapZoomInToolClass();


pZoomIn.OnCreate(axMapControl1.Object);


axMapControl1.CurrentTool = pZoomIn as ITool;


}


private void 缩小ToolStripMenuItem_Click(object sender, EventArgs e)
{
ICommand pZoomOut = new ControlsMapZoomOutToolClass();


pZoomOut.OnCreate(axMapControl1.Object);



}

axMapControl1.CurrentTool = pZoomOut as ITool;


通过运行程序,发现和 toolbarcontrol 的效果一样


2、12另一 个视 图控 件 PageLayoutControl


在 ArcMap 中除了在介绍 MapControl 控件的时候提到的数据视图,还有另外一种视图,就
是布局视图(Layout),PageLlayoutControl 控件则对应了 ArcMap 中的布局视图。
PageLayoutControl 控件主要用于制图,它可以方便的操作各种元素对象,以产生一副精美的
地图对象出来。该控件中封装了一个 Pag eLayout 对象,这个对象用于控制布局视图中的对
象的属性。


2、13 MapControl 控件与 PageLayout 控件的联动


分析:要实现这两个控件的联动,我们首先回顾下 ArcMap 中的情景,两个控件的联动不仅
仅是简单的切换,在切换的时候还因该保留各自控件上的一些状态,比如说当我们在
MapControl 上有一个放大操作时,当我们没有将这个放大操作取消而切换到 PageLayout 控
件,在 PageLayout 控件上做了一些操作后,又切换到 MapControl 控件,我们应该还应该能
进行放大操作而不用重新使用放大这个工具。


通过分析我们可以得到下面几点:


当切换两个控件的时候,地图的同步


各自控件上激活的工具或者命令的保留


当存在 TOC 控件和 ToolBar 控件的时候,切换了地图控件和布局控件,那么这两个控件的伙
伴控件也应发生变化。

在 Form 中添加 TabControl 控

相关主题
文本预览
相关文档 最新文档