ArcEngine|加载不同类型文档并实现TOCControl的右键菜单

所有的代码已经传到了我的GitHub,需要的请自取,GitHub项目地址:https://github.com/Weltra/T_ArcMap

MapControl中加载不同类型文档

加载ShapeFile

在file选项下添加Open file选项,并在其子选项中添加Open Shapefile选项。为其绑定Click事件。

image-20230314151618218 image-20230314152736989

在Click事件的方法中添加代码,实现加载shape的功能。

 private void openShapefileToolStripMenuItem_Click(object sender, EventArgs e)
 {
     OpenFileDialog openshapeFileDialog = new OpenFileDialog();
     openshapeFileDialog.Filter = "地图文档(*.shp)|*.shp";
     openshapeFileDialog.Title = "Selcet a ShapeFile";
     if (openshapeFileDialog.ShowDialog() == DialogResult.OK)
     {
         string FilePath = openshapeFileDialog.FileName;
         string FileName = openshapeFileDialog.SafeFileName;
         string WorkspacePath = FilePath.Replace(FileName,"");

         IWorkspaceFactory shapefileworkspace = new ShapefileWorkspaceFactory();
         IFeatureWorkspace pWorkSpace = shapefileworkspace.OpenFromFile(WorkspacePath, 0) as IFeatureWorkspace;

         IFeatureClass pfeatureclass = pWorkSpace.OpenFeatureClass(FileName);
         IFeatureLayer featureLayer = new FeatureLayer();

         featureLayer.FeatureClass = pfeatureclass;
         featureLayer.Name = pfeatureclass.AliasName;
         featureLayer.Visible = true;

         IMap pmap = axMapControl1.Map;
         pmap.AddLayer(featureLayer);
         axMapControl1.ActiveView.Refresh();
     }
 }

封装加载空间数据库方法

新建一个FileClass,封装加载空间数据库方法:AddAllDataset函数,以便对其他空间数据库加载时直接调用。

 class FileClass
 {
     //封装加载空间数据库方法:AddAllDataset函数,以便对其他空间数据库加载时直接调用。
     public static void AddAllDataset(IWorkspace pWorkspace, AxMapControl mapControl)
     {
         IEnumDataset pEnumDataset = pWorkspace.get_Datasets(ESRI.ArcGIS.Geodatabase.esriDatasetType.esriDTAny);
         pEnumDataset.Reset();
         //将Enum数据集集中的数据一个一个地读到dataset 中
         IDataset pDataset = pEnumDataset.Next();
         //判断数据集是否有数据
         while (pDataset != null)
         {
             if (pDataset is IFeatureDataset)//要素数据集
             {
                 IFeatureWorkspace pFeatureWorkspac = (IFeatureWorkspace)pWorkspace;
                 IFeatureDataset pFeatureDataset = pFeatureWorkspac.OpenFeatureDataset(pDataset.Name);
                 IEnumDataset pEnumDataset1 = pFeatureDataset.Subsets;
                 pEnumDataset1.Reset();
                 IGroupLayer pGroupLayer = new GroupLayerClass();
                 pGroupLayer.Name = pFeatureDataset.Name;
                 IDataset pDataset1 = pEnumDataset1.Next();
                 while (pDataset1 != null)
                 {
                     if (pDataset1 is IFeatureClass)//要素类
                     {
                         IFeatureLayer pFeatureLayer = new FeatureLayerClass();
                         pFeatureLayer.FeatureClass = pFeatureWorkspac.OpenFeatureClass(pDataset1.Name);
                         if (pFeatureLayer.FeatureClass != null)
                         {
                             pFeatureLayer.Name = pFeatureLayer.FeatureClass.AliasName;
                             pGroupLayer.Add(pFeatureLayer);
                             mapControl.Map.AddLayer(pFeatureLayer);
                         }
                     }
                     pDataset1 = pEnumDataset1.Next();
                 }
             }
             else if (pDataset is IFeatureClass)//要素类
             {
                 IFeatureWorkspace pFeatureWorkspace = (IFeatureWorkspace)pWorkspace;
                 IFeatureLayer pFeatureLayer = new FeatureLayerClass();
                 pFeatureLayer.FeatureClass = pFeatureWorkspace.OpenFeatureClass(pDataset.Name);
                 pFeatureLayer.Name = pFeatureLayer.FeatureClass.AliasName;
                 mapControl.Map.AddLayer(pFeatureLayer);
             }
             else if (pDataset is IRasterDataset)//栅格数据
             {
                 IRasterWorkspaceEx pRasterWorkspace = (IRasterWorkspaceEx)pWorkspace;
                 IRasterDataset pRasterDataset = pRasterWorkspace.OpenRasterDataset(pDataset.Name);
                 //影像金字塔的判断和创建
                 IRasterPyramid3 pRasterPyramid;
                 pRasterPyramid = pRasterDataset as IRasterPyramid3;
                 if (pRasterPyramid != null)
                 {
                     if (!(pRasterPyramid.Present))
                     {
                         pRasterPyramid.Create();//创建金字塔
                     }
                 }
                 IRasterLayer pRasterLayer = new RasterLayerClass();
                 pRasterLayer.CreateFromDataset(pRasterDataset);
                 ILayer pLayer = pRasterLayer as ILayer;//进行继承
                 mapControl.AddLayer(pLayer, 0);
             }
             pDataset = pEnumDataset.Next();
         }
         mapControl.ActiveView.Refresh();
         //同步鹰眼
         // SynchronizeEagleEye();
     }
 }

加载Access Geodatabase

在Open file选项的子选项中添加Open mdb file选项,为其绑定Click事件。在Click事件处理方法中添加代码,实现加载Access Geodatabase的功能。

image-20230314151618218 image-20230314152807106

在Click事件的方法中添加代码,实现加载mdb的功能。

private void openMdbFileToolStripMenuItem_Click(object sender, EventArgs e)
{
    OpenFileDialog pOpenFileDialog = new OpenFileDialog();
    pOpenFileDialog.Title = "打开PersonGeoDatabase文件";
    pOpenFileDialog.Filter = "Personal GeoDatabase(*.mdb)|*.mdb";
    pOpenFileDialog.ShowDialog();
    string pFullPath = pOpenFileDialog.FileName;
    if (pFullPath == "") return;
    AccessWorkspaceFactory pAccessWorkspaceFactory = new AccessWorkspaceFactory();
    //获取工作空间
    IWorkspace pWorkspace = pAccessWorkspaceFactory.OpenFromFile(pFullPath, 0);
    //ClearAllData();
    FileClass.AddAllDataset(pWorkspace, axMapControl1);
}

加载File Geodatabase

在Open file选项的子选项中添加Open gdb file选项,为其绑定Click事件。在Click事件处理方法中添加代码,实现加载File Geodatabase的功能。

image-20230314151618218 image-20230314152846297

在Click事件的方法中添加代码,实现加载gdb的功能。

private void openGdbFileToolStripMenuItem_Click(object sender, EventArgs e)
{
    FolderBrowserDialog dlg = new System.Windows.Forms.FolderBrowserDialog();
    if (dlg.ShowDialog() != DialogResult.OK) return;
    string pFullth = dlg.SelectedPath;
    if (pFullth == "") return;
    //使用esri.arcgis.DataSourseGDB
    FileGDBWorkspaceFactory pFileGDBWorkspaceFactory = new FileGDBWorkspaceFactory();
    //ClearAllData();
    //获取工作空间
    IWorkspace pWorkspac = pFileGDBWorkspaceFactory.OpenFromFile(pFullth, 0);
    FileClass.AddAllDataset(pWorkspac, axMapControl1);
}

实现右键菜单栏

添加ContextMenuStrip1控件,并在在该上下文菜单中添加“移除(R)”和“打开属性表(T)”菜单项。

image-20230315211558261

添加ContextMenuStrip2控件,并在在该上下文菜单中添加“添加数据(T)”、“打开所有图层(Y)”和“关闭所有图层(L)”菜单项。

image-20230315211902289

添加ContextMenuStrip3控件,并在在该上下文菜单中添加“更改颜色(C)”菜单项。

image-20230315212312597

首先添加axTOCControl1的OnMouseDown事件。选中窗体上axTOCControl1,双击添加OnMouseDown事件。

image-20230315204712716

在图层处右击会弹出上下文菜单,移除和打开属性表都是针对所选图层来操作的,ITOCControl.HitTest方法可以使我们在Engine中鼠标右击TocControl时得到选择的图层。声明 m_Layer为全局变量,然后在OnMouseDown事件中添加如下代码。

private void axTOCControl1_OnMouseDown(object sender, ESRI.ArcGIS.Controls.ITOCControlEvents_OnMouseDownEvent e)
{
    if (e.button == 2)
    {
        ESRI.ArcGIS.Controls.esriTOCControlItem Item = ESRI.ArcGIS.Controls.esriTOCControlItem.esriTOCControlItemNone;
        IBasicMap pBasicMap = null;
        ILayer pLayer = null;
        object other = null;
        object index = null;
        axTOCControl1.HitTest(e.x, e.y, ref Item, ref pBasicMap, ref pLayer, ref other, ref index);
        m_Layer = pLayer;
        switch (Item) 
        {
            case ESRI.ArcGIS.Controls.esriTOCControlItem.esriTOCControlItemHeading:
                contextMenuStrip2.Show(axTOCControl1, new System.Drawing.Point(e.x, e.y));
                break;
            case ESRI.ArcGIS.Controls.esriTOCControlItem.esriTOCControlItemLayer:
                contextMenuStrip1.Show(axTOCControl1, new System.Drawing.Point(e.x, e.y));
                break;
            case ESRI.ArcGIS.Controls.esriTOCControlItem.esriTOCControlItemLegendClass:
                contextMenuStrip3.Show(axTOCControl1, new System.Drawing.Point(e.x, e.y));
                break;
            case ESRI.ArcGIS.Controls.esriTOCControlItem.esriTOCControlItemMap:
                contextMenuStrip4.Show(axTOCControl1, new System.Drawing.Point(e.x, e.y));
                break;
            case ESRI.ArcGIS.Controls.esriTOCControlItem.esriTOCControlItemNone:
                contextMenuStrip5.Show(axTOCControl1, new System.Drawing.Point(e.x, e.y));
                break;
        }
    }
}

实现Remove Layer

首先添加该菜单项的Click事件,然后在“Remove Layer”的Click事件中添加如下代码。

private void 移除ToolStripMenuItem_Click(object sender, EventArgs e)
{
    axMapControl1.Map.DeleteLayer(m_Layer);
}

实现Open Atrribute Table

首先添加该菜单项的Click事件,然后需要新建窗体用来显示属性表。具体为选中该工程右击,下拉列表中选择Add->Windows Form,为其窗体命名为“Attribute_Table”,点击“Add”。为新建窗体添加DataGridView,然后选中该DataGridView,设置其Dock选项为Fill。

image-20230315124722296

为窗体的Load事件添加代码。该事件处理主要是从图层中读取要素类的属性信息,并且显示到DataGridView控件中。

private void Atrribute_Table_Load(object sender, EventArgs e)
{
    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(CoClass.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();
    }
}

因为ESRI的数据类型和系统数据类型有所区别,因此需要事先进行类型转换,将其封装在类CoClass中,通过ParseFieldType方法来实现:

class CoClass
{
    //将ESRI类型转为系统类���
    public static string ParseFieldType(esriFieldType fieldType)
    {
        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";
        }
    }
}

在mainForm.cs的OpenAttributeTable的Click事件中添加代码。

private void OpenAttributeTableToolStripMenuItem1_Click(object sender, EventArgs e)
{
	AttributeTable pAttributeTable = new AttributeTable(globe_Layer as IFeatureLayer);
	pAttributeTable.Show();
}

结果

加载地图文档

加载ShapeFile

image-20230315214301819 image-20230315213942451

加载Access Geodatabase

image-20230315214344890 image-20230315214435114

加载File Geodatabase

image-20230315221443121 image-20230315221456928

TocControl图层控制

针对Layer

移除
image-20230315221247288 image-20230315221309723
打开属性表
image-20230315221229532

针对Map

image-20230315221517302

针对LegendClass

image-20230315221531459

总结

简述工厂模式

工厂模式主要是为创建对象提供接口,将创建对象的过程隔离起来,实现了创建者与调用者的分离,提高了程序的灵活性。

核心本质:

实例化对象,用工厂方法代替new操作。

将选择实现类、创建对象统一管理和控制,从而将调用者跟我们实现类解耦。

加载Shape的步骤

创建工作空间工厂

打开shapefile工作空间

打开要素类

创建要素图层

关联图层和要素类

添加到地图空间

TocControl提供的HitTest方法的主要作用?

ITOCControl接口的HitTest()方法可以返回TOCControl中点击坐标点处的对象类型ItemType。具体定义如下:

public void HitTest ( int X, int Y, ref esriTOCControlItem ItemType, ref IBasicMap BasicMap, ref ILayer Layer, ref object Unk, ref object Data );

各参数的含义如下:

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

esriTOCControlItem枚举常量用于描述TocControl上的Item的类型,其定义如下:

image-20230317102227718
posted @ 2023-03-17 10:30  Weltㅤ  阅读(282)  评论(0编辑  收藏  举报