ArcEngine空间编辑(开始编辑与选择要素举例)

最近琢磨了一下ArcEngine的空间编辑功能,包括开始/保存/结束编辑,选择要素,移动要素,删除要素,剪切要素,粘贴要素,添加要素,点线面的绘画,属性编辑,撤销和恢复着几项。其实这些空间编辑功能有一些是可以直接调用类库命令来进行编辑的,有些是需要自定义一个继承了ICommand和ITool的类来添加命令。 

我在这里就举以上选择要素的例子来说明如何自定义类来添加命令。首先介绍一下开始编辑。

一、开始编辑

在开始编辑之前我们必须要选定图层,即对那个图层进行编辑命令,所以在窗口上需要添加一个ComboBox控件,用来选择需要编辑的图层。我们需要将加载出来的mxd文件中的各个图层名放入ComboBox中。

1、定义一个函数用于获取当前地图文档所有图层集合,具体函数如下:

        /// <summary>
        /// 获取当前地图文档所有图层集合
        /// </summary>
        /// <param name="pMap"></param>
        /// <returns></returns>
        public static List<ILayer> GetLayers(IMap pMap)
        {
            ILayer plyr = null;
            List<ILayer> pLstLayers = null;
            try
            {
                pLstLayers = new List<ILayer>();
                for (int i = 0; i < pMap.LayerCount; i++)
                {
                    plyr = pMap.get_Layer(i);
                    if (!pLstLayers.Contains(plyr))
                    {
                        pLstLayers.Add(plyr);
                    }
                }
            }
            catch (Exception ex)
            { }
            return pLstLayers;
        }

2、设置ComboBox的SelectedIndexChanged事件

在写ComboBox的SelectedIndexChanged事件之前需要先定义一些全局变量

private IFeatureLayer pCurrentLyr = null;

private IEngineEditLayers pEngineEditLayers = null;

定义完后我们来写这个事件:

        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            string sLyrName = cmbSelLayer.SelectedItem.ToString();
            pCurrentLyr = MapManager.GetLayerByName(pMap, sLyrName) as IFeatureLayer;
            //设置编辑目标图层
            pEngineEditLayers.SetTargetLayer(pCurrentLyr, 0);
        }

3、通过单击ComboBox来获取各个图层名

同样的需要先定义各个变量:

        private IMap pMap = null;

        private IActiveView pActiveView = null;

        private List<ILayer> plstLayers = null;
单击ComboBox获取图层名:

        private void cmbSelLayer_Click(object sender, EventArgs e)
        {
            pMap = axMapControl1.Map;
            pActiveView = pMap as IActiveView;
            plstLayers = MapManager.GetLayers(pMap);
            //List<ILayer> plstLyt = new List<ILayer>();
            cmbSelLayer.Items.Clear();
            for (int i = 0; i < plstLayers.Count; i++)
            {
                if (!cmbSelLayer.Items.Contains(plstLayers[i].Name))
                {
                    cmbSelLayer.Items.Add(plstLayers[i].Name);
                }
            }
            if (cmbSelLayer.Items.Count != 0) cmbSelLayer.SelectedIndex = 0;
        }

4、获取到图层名之后就可以点击“开始编辑”按钮开始编辑

当然依旧不要忘了定义变量,我这里就不列出来了,形式如上面两个一样。

其中ChangeButtonState()是自定义的控制各个按钮是否Enable的函数,未开始编辑之前为false,开始编辑之后为true。

        /// <summary>
        /// 开始编辑
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnStartEdit_Click(object sender, EventArgs e)
        {
            try
            {
                if (plstLayers == null || plstLayers.Count == 0)
                {
                    MessageBox.Show("请加载编辑图层!", "提示",MessageBoxButtons.OK, MessageBoxIcon.Information);
                    return;
                }

                pMap.ClearSelection();
                pActiveView.Refresh();
                //InitComboBox(plstLayers);
                ChangeButtonState(true);
                //如果编辑已经开始,则直接退出
                if (pEngineEditor.EditState != esriEngineEditState.esriEngineStateNotEditing)
                    return;
                if (pCurrentLyr == null) return;
                //获取当前编辑图层工作空间
                IDataset pDataSet = pCurrentLyr.FeatureClass as IDataset;
                IWorkspace pWs = pDataSet.Workspace;
                //设置编辑模式,如果是ArcSDE采用版本模式
                if (pWs.Type == esriWorkspaceType.esriRemoteDatabaseWorkspace)
                {
                    pEngineEditor.EditSessionMode = esriEngineEditSessionMode.esriEngineEditSessionModeVersioned;
                }
                else
                {
                    pEngineEditor.EditSessionMode = esriEngineEditSessionMode.esriEngineEditSessionModeNonVersioned;
                }
                //设置编辑任务
                pEngineEditTask = pEngineEditor.GetTaskByUniqueName("ControlToolsEditing_CreateNewFeatureTask");
                pEngineEditor.CurrentTask = pEngineEditTask;// 设置编辑任务
                pEngineEditor.EnableUndoRedo(true); //是否可以进行撤销、恢复操作
                pEngineEditor.StartEditing(pWs, pMap); //开始编辑操作
            }
            catch (Exception ex)
            {
            }
        }

二、选择要素

开始编辑之后就可以选择要素了。在工程中新建一个SelectFeatureToolClass类。
1、引用
using ESRI.ArcGIS.SystemUI;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Controls;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.Display;

2、继承ICommand和ITool接口,定义全局变量

        private IMap m_Map = null;
        private bool bEnable = true;
        private IHookHelper m_hookHelper = null;
        private IActiveView m_activeView = null;
        private IEngineEditor m_EngineEditor = null;
        private IEngineEditLayers m_EngineEditLayers = null;

3、ITool接口的成员实现:

        #region ITool 成员

        public int Cursor
        {
            get { return -1; }
        }

        public bool Deactivate()
        {
            return true;
        }

        public bool OnContextMenu(int x, int y)
        {
            return false;
        }

        public void OnDblClick()
        {

        }

        public void OnKeyDown(int keyCode, int shift)
        {

        }

        public void OnKeyUp(int keyCode, int shift)
        {

        }

        public void OnMouseDown(int button, int shift, int x, int y)
        {
            try
            {
                if (m_EngineEditor == null) return;
                if (m_EngineEditor.EditState != esriEngineEditState.esriEngineStateEditing) return;
                if (m_EngineEditLayers == null) return;
                //获取目标图层
                IFeatureLayer pFeatLyr = m_EngineEditLayers.TargetLayer;
                IFeatureClass pFeatCls = pFeatLyr.FeatureClass;
                //获取地图上的坐标点
                IPoint pPt = m_activeView.ScreenDisplay.DisplayTransformation.ToMapPoint(x, y);
                IGeometry pGeometry = pPt as IGeometry;
                double dLength = 0;
                ITopologicalOperator pTopo = pGeometry as ITopologicalOperator;
                //设置选择过滤条件
                ISpatialFilter pSpatialFilter = new SpatialFilterClass();
                //不同的图层类型设置不同的过滤条件
                switch (pFeatCls.ShapeType)
                {
                    case esriGeometryType.esriGeometryPoint:
                        //将像素距离转换为地图单位距离
                        dLength = MapManager.ConvertPixelsToMapUnits(m_activeView, 8);
                        pSpatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelContains;
                        break;
                    case esriGeometryType.esriGeometryPolygon:
                        dLength = MapManager.ConvertPixelsToMapUnits(m_activeView, 4);
                        pSpatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects;
                        break;
                    case esriGeometryType.esriGeometryPolyline:
                        dLength = MapManager.ConvertPixelsToMapUnits(m_activeView, 4);
                        pSpatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelCrosses;
                        break;
                }
                //根据过滤条件进行缓冲
                IGeometry pBuffer = null;
                pBuffer = pTopo.Buffer(dLength);
                pGeometry = pBuffer.Envelope as IGeometry;
                pSpatialFilter.Geometry = pGeometry;
                pSpatialFilter.GeometryField = pFeatCls.ShapeFieldName;
                IQueryFilter pQueryFilter = pSpatialFilter as IQueryFilter;
                //根据过滤条件进行查询
                IFeatureCursor pFeatCursor = pFeatCls.Search(pQueryFilter, false);
                IFeature pFeature = pFeatCursor.NextFeature();
                while (pFeature != null)
                {
                    //获取地图选择集
                    m_Map.SelectFeature(pFeatLyr as ILayer, pFeature);
                    pFeature = pFeatCursor.NextFeature();
                }
                m_activeView.PartialRefresh(esriViewDrawPhase.esriViewGeoSelection, null, null);
                System.Runtime.InteropServices.Marshal.ReleaseComObject(pFeatCursor);
            }
            catch (Exception ex)
            {

            }
        }

        public void OnMouseMove(int button, int shift, int x, int y)
        {
        }

        public void OnMouseUp(int button, int shift, int x, int y)
        {
        }

        public void Refresh(int hdc)
        {
        }

        #endregion

其中OnMouseDown是鼠标按下时所发生的事件。

4、ICommand接口的成员实现:
        #region ICommand 成员

        public int Bitmap
        {
            get { return -1; }
        }

        public string Caption
        {
            get { return "选择要素"; }
        }

        public string Category
        {
            get { return "编辑工具"; }
        }

        public bool Checked
        {
            get { return false; }
        }

        public bool Enabled
        {
            get { return bEnable; }
        }

        public int HelpContextID
        {
            get { return -1; }
        }

        public string HelpFile
        {
            get { return ""; }
        }
        public string Message
        {
            get { return "选择要素"; }
        }

        public string Name
        {
            get { return "SelectFeatureTool"; }
        }

        public void OnClick()
        {
            m_Map = m_hookHelper.FocusMap;
            m_activeView = m_Map as IActiveView;
            m_EngineEditor = MapManager.EngineEditor;
            m_EngineEditLayers = MapManager.EngineEditor as IEngineEditLayers;
            //EditVertexClass.ClearResource();
        }

        public void OnCreate(object Hook)
        {
            if (Hook == null) return;
            try
            {
                m_hookHelper = new HookHelperClass();
                m_hookHelper.Hook = Hook;
                if (m_hookHelper.ActiveView == null)
                    m_hookHelper = null;
            }
            catch
            {
                m_hookHelper = null;
            }

            if (m_hookHelper == null)
                bEnable = false;
            else
                bEnable = true;
        }

        public string Tooltip
        {
            get { return "选择要素"; }
        }

        #endregion

需要注意的是,ICommand和ITool接口中的所有函数都得写上去实现,否则报错。

那么现在自定义的SelectFeatureToolClass类就写好了,接下来只要调用这个类就可以实现对图层要素的选择。
5、“选择要素”按钮的Click事件
        /// <summary>
        /// 选择要素
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSelectedEdit_Click(object sender, EventArgs e)
        {
            try
            {
                ////调用类库
                //axMapControl1.CurrentTool = null;
                //ControlsSelectFeaturesTool pTool = new ControlsSelectFeaturesToolClass();
                //pTool.OnCreate(axMapControl1.Object);
                //axMapControl1.CurrentTool = pTool as ITool;
                

                ICommand m_SelTool = new SelectFeatureToolClass();
                m_SelTool.OnCreate(axMapControl1.Object);
                m_SelTool.OnClick();
                axMapControl1.CurrentTool = m_SelTool as ITool;
                axMapControl1.MousePointer = esriControlsMousePointer.esriPointerArrow;
            }
            catch (Exception ex)
            {
            }
        }

从上面的代码中可以看出,还有一个调用类库的方法。调用类库的方法其实也可以,但是和自定义函数的是有区别的。

用调用类库的方法进行选择要素无视对图层的选择,所有的图层上的要素都可以进行选择;自定义类方法进行选择要素是根据选择的图层进行选择,不是当前ComboBox中的当前图层不会进行选中。
当然,调用类库的方法也可以根据当前图来选择,不过我还没写出来,如果知道如何写的大佬们请务必告知,交流知识经验嘛。
关于其他例如移动要素啊删除要素啊之类的方法如同选择要素,就是自定义类,然后调用。当然这些都是在选择要素的基础上进行的,不先选择怎么移动和删除对不对。
如果有空的话我会再写其他有关空间编辑的操作,今天就先这样。

转载自:https://blog.csdn.net/knqiufan/article/details/77855211

You may also like...