至此,已经可以利用鼠标调整TOCControl中图层的显示顺序,而位于主视图中的地图显示顺序也会进行相应调整。
(2)点击鼠标右键显示所在图层的属性表内容
在ArcMap中,“Table of Contents”中右键菜单功能非常丰富,在利用ArcGIS Engine进行GIS软件开发时,TOCControl控件本身并没有提供右键菜单功能,需要通过自己编程来实现。本实例实现了在TOCControl控件中点击鼠标右键,选择图层,弹出所选图层属性表的功能,软件开发的基本思路如下:
A. 利用鼠标点击,选择需要打开属性表的图层; B. 根据所选择的图层,创建数据表; C. 新建一个窗体对象,在其上放置DataGridView控件,利用它打开创建的属性表。 ?利用鼠标右键选择需要打开属性表的图层
在axTOCControl1的OnMouseDown事件中,添加下列代码,以便选择需要打开其属性表的图层。
else if (e.button == 2)//探测鼠标右键按下 {
//鼠标右键按下
if (axMapControl1.LayerCount > 0)//主视图中要有地理数据 {
esriTOCControlItem mItem = new esriTOCControlItem(); IBasicMap pMap = new MapClass(); ILayer pLayer = new FeatureLayerClass(); object pOther = new object(); object pIndex = new object();
axTOCControl1.HitTest(e.x, e.y, ref mItem, ref pMap, ref pLayer, ref pOther, ref pIndex);
IGeoFeatureLayer pGeoFeatureLayer;
pGeoFeatureLayer = (IGeoFeatureLayer)pLayer; //添加显示属性表的代码 }
}
?根据所选图层创建数据表
public static System.Data.DataTable CreateDataTable(ILayer pLayer, string tableName) {
//根据选择的图层创建空DataTable
System.Data.DataTable pDataTable = CreateDataTableByLayer(pLayer, tableName); pDataTable.TableName = pLayer.Name; //取得图层类型
string shapeType = getShapeType(pLayer); //创建DataTable的行对象 DataRow pDataRow = null; //从ILayer查询到ITable
ITable pTable = pLayer as ITable;
ICursor pCursor = pTable.Search(null, false); //取得ITable中的行信息
IRow pRow = pCursor.NextRow(); int n = 0;
while (pRow != null) {
//新建DataTable的行对象
pDataRow = pDataTable.NewRow();
for (int i = 0; i < pRow.Fields.FieldCount; i++) {
//如果字段类型为esriFieldTypeGeometry,则根据图层类型设置字段值
if (pRow.Fields.get_Field(i).Type == esriFieldType.esriFieldTypeGeometry) {
pDataRow[i] = shapeType; }
//当图层类型为Anotation时,要素类中会有esriFieldTypeBlob类型的数据, //其存储的是标注内容,如此情况需将对应的字段值设置为Element
else if (pRow.Fields.get_Field(i).Type == esriFieldType.esriFieldTypeBlob) {
pDataRow[i] = \; } else {
pDataRow[i] = pRow.get_Value(i); } }
//添加DataRow到DataTable pDataTable.Rows.Add(pDataRow); pDataRow = null; n++;
pRow = pCursor.NextRow(); }
return pDataTable;
}
应该将上述方法封装在一个类里面。假设封装在GeoMapLoad类里。该方法还调用了一个方法getShapeType,用于确定图层的类型,即判断图层是属于点图层、线图层,还是面图层。
public static string getShapeType(ILayer pLayer) {
IFeatureLayer pFeatLyr = (IFeatureLayer)pLayer; switch (pFeatLyr.FeatureClass.ShapeType) {
case esriGeometryType.esriGeometryPoint: return \;
case esriGeometryType.esriGeometryPolyline: return \;
case esriGeometryType.esriGeometryPolygon: return \; default: return \; }
}
创建空表的方法如下:
private static System.Data.DataTable CreateDataTableByLayer(ILayer pLayer, string tableName) {
//创建一个DataTable表
System.Data.DataTable pDataTable = new System.Data.DataTable(tableName); //取得ITable接口
ITable pTable = pLayer as ITable; IField pField = null; DataColumn pDataColumn;
//根据每个字段的属性建立DataColumn对象
for (int i = 0; i < pTable.Fields.FieldCount; i++) {
pField = pTable.Fields.get_Field(i); //新建一个DataColumn并设置其属性
pDataColumn = new DataColumn(pField.Name); if (pField.Name == pTable.OIDFieldName) {
pDataColumn.Unique = true;//字段值是否唯一 }
//字段值是否允许为空
pDataColumn.AllowDBNull = pField.IsNullable; //字段别名
pDataColumn.Caption = pField.AliasName; //字段数据类型
pDataColumn.DataType = System.Type.GetType(ParseFieldType(pField.Type)); //字段默认值
pDataColumn.DefaultValue = pField.DefaultValue; //当字段为String类型是设置字段长度 if (pField.VarType == 8) {
pDataColumn.MaxLength = pField.Length; }
//字段添加到表中
pDataTable.Columns.Add(pDataColumn); pField = null; pDataColumn = null; }
return pDataTable;
}
public static string ParseFieldType(esriFieldType fieldType) {
switch (fieldType) {
case esriFieldType.esriFieldTypeBlob: return \;
case esriFieldType.esriFieldTypeDate: return \;
case esriFieldType.esriFieldTypeDouble: return \;
case esriFieldType.esriFieldTypeGeometry: return \;
case esriFieldType.esriFieldTypeGlobalID: return \;
case esriFieldType.esriFieldTypeGUID: return \;
case esriFieldType.esriFieldTypeInteger: return \;
case esriFieldType.esriFieldTypeOID: return \;
case esriFieldType.esriFieldTypeRaster: return \;
case esriFieldType.esriFieldTypeSingle: return \;
case esriFieldType.esriFieldTypeSmallInteger: return \;
case esriFieldType.esriFieldTypeString: return \; default:
return \; }
}
//因为DataTable的表名不允许含有“.”,因此我们用“_”替换。函数如下: public static string getValidFeatureClassName(string FCname) {
int dot = FCname.IndexOf(\); if (dot != -1) {
return FCname.Replace(\, \); }
return FCname;
}
?显示选择图层的属性表。需要新添加一个窗体,在本例中为GeoMapAttribute,在窗体上添加DataGridView控件,并将其Modifiers属性改为Public。利用下面的代码,就能将所选图层的属性表显示出来。这部分代码应放在第一步选择目标图层的代码后面。
string layerPath; string layerDatafileName; IWorkspaceName pWorkspaceName; IDatasetName pDatasetName; IDataLayer pDataLayer;
pDataLayer = pGeoFeatureLayer as IDataLayer;
pDatasetName = pDataLayer.DataSourceName as IDatasetName; pWorkspaceName = pDatasetName.WorkspaceName; layerPath = pWorkspaceName.PathName;
layerDatafileName = pLayer.Name.Trim() + \; string dbfFilePath = layerPath; ; string dbfFileName = layerDatafileName; ;
IWorkspaceFactory pWorkspaceFactory = new ShapefileWorkspaceFactoryClass(); IWorkspace pWorkspace = pWorkspaceFactory.OpenFromFile(dbfFilePath, 0); IFeatureWorkspace pFeatureWorkspace = pWorkspace as IFeatureWorkspace; if (pFeatureWorkspace != null) {
IFeatureClass pFeatureClass = pFeatureWorkspace.OpenFeatureClass(dbfFileName); if (pFeatureClass != null) {
DataTable dt = new DataTable(); DataColumn dc;
for (int i = 0; i <= pFeatureClass.Fields.FieldCount - 1; i++) {
dc = new DataColumn(pFeatureClass.Fields.get_Field(i).Name); dt.Columns.Add(dc); }
IFeatureCursor pFeatureCursor = pFeatureClass.Search(null, false); IFeature pFeature = pFeatureCursor.NextFeature(); DataRow dr;
while (pFeature != null) {
dr = dt.NewRow();
for (int j = 0; j <= pFeatureClass.Fields.FieldCount - 1; j++) {
if (pFeatureClass.FindField(pFeatureClass.ShapeFieldName) == j) {
dr[j] = pFeatureClass.ShapeType.ToString(); } else {