组件GIS 1 地图操作

v20200614:TOC右键菜单“栅格图层”和“矢量图层”区别显示;获取属性表代码小优化;

v20200622:内容调整,重写优化;(该死的强迫症)

1.1 纲要

1.1.1 思维导图

地图操作

1.1.2 接口、类、枚举

  • AxMapControl,AxPageLayoutControl,AxTOCControl,axLicenseControl,IHookHelper(ESRI.ArcGIS.Controls)/(ESRI.ArcGIS.AxControls)
  • IMapDocument,IActiveView,IMap,ILayer,IFeatureLayer,IRasterLayer,IExtentStack(ESRI.ArcGIS.Carto)
  • IWorkspaceFactory,IWorkspace,IFeatureWorkspace,IEnumDataset,IDataset,IFeatureDataset,IFeatureClass,esriDatasetType(ESRI.ArcGIS.Geodatabase)
  • IObjectCopy,esriUnits(ESRI.ArcGIS.esriSystem)
  • ICommand,ITool,ISystemMouseCursor,esriSystemMouseCursor(ESRI.ArcGIS.SystemUI)
  • IEnvelope(ESRI.ArcGIS.Geometry)
  • IDisplayTransformation(ESRI.ArcGIS.Display)

1.2 布局

利用TabControl、ToolStrip、SplitContainer、StatusStrip控件划分菜单区、图层管理区、视图区、状态栏。再加上ArcGIS的MapControl、PageLayoutControl、TOCControl、LicenseControl。最后在Program.cs内添加Runtime许可代码ESRI.ArcGIS.RuntimeManager.Bind(ESRI.ArcGIS.ProductCode.EngineOrDesktop);

每一个TabPage内镶嵌MenuStrip(支持快捷键,没有分割线,没有label控件)或者ToolStrip(不支持快捷键);每一个菜单项图标标来源于项目资源文件。

主界面

image-20200622094637112

1.3 文件管理

image-20200622144235628

1.3.1 数据加载

axMapControl控件提供axMapControl.AddLayer(); axMapControl.AddLayerFromFile(); axMapControl.AddShapeFile();三种方法。.shp .lyr文件可以直接调用方法传入路径即可,栅格数据需要调用IRasterLayer.CreateFromFilePath(FileName); 方法获取栅格图层,然后调用axMapControl.AddLayer()即可。

加载.shp矢量数据

if (ofdAddShp.ShowDialog() == DialogResult.OK)
{
    string[] fileName = ofdAddShp.SafeFileNames;//无路径文件名
    string path = System.IO.Path.GetDirectoryName(ofdAddShp.FileName);//得到文件夹路径
    for (int i = 0; i < fileName.Length; i++)
        axMapControl.AddShapeFile(path, fileName[i]);
}

加载栅格数据

if (ofdAddRaster.ShowDialog() == DialogResult.OK)
{
    for (int i = 0; i < ofdAddRaster.FileNames.Length; i++)
    {
        IRasterLayer pRasterLayer = new RasterLayerClass();
        pRasterLayer.CreateFromFilePath(ofdAddRaster.FileNames[i]);
        axMapControl.AddLayer(pRasterLayer);
    }
}

1.3.2 地图文档的新建、打开、保存

mxd新建

IMap map = new MapClass();
axMapControl.Map = map;

mxd打开

if (ofdOpenMxd.ShowDialog() == DialogResult.OK)
    axMapControl.LoadMxFile(ofdOpenMxd.FileName);

mxd保存

string sMxdFileName = axMapControl.DocumentFilename;
if (sMxdFileName == null || sMxdFileName == string.Empty)
{
    string sRelPath = Application.StartupPath + @"........Data";
    string sAbsPath = System.IO.Path.GetFullPath(sRelPath);
    SaveFileDialog pSaveFileDialog = new SaveFileDialog();
    pSaveFileDialog.Title = "请选择保存路径";
    pSaveFileDialog.InitialDirectory = sAbsPath;
    pSaveFileDialog.OverwritePrompt = true;
    pSaveFileDialog.Filter = "ArcMap文档(*.mxd)|*.mxd|ArcMap模板(*.mxt)|*.mxt";
    if (pSaveFileDialog.ShowDialog() == DialogResult.OK)
        sMxdFileName = pSaveFileDialog.FileName;
    else
        return;
}
IMapDocument pMapDocument = new MapDocumentClass();
pMapDocument.New(sMxdFileName);
pMapDocument.ReplaceContents(axMapControl.Map as IMxdContents);
pMapDocument.Save();
MessageBox.Show("保存地图文档成功!");

mxd另存为

string sRelPath = Application.StartupPath + @"........Data";
string sAbsPath = System.IO.Path.GetFullPath(sRelPath);
SaveFileDialog pSaveFileDialog = new SaveFileDialog();
pSaveFileDialog.Title = "请选择保存路径";
pSaveFileDialog.InitialDirectory = sAbsPath;
pSaveFileDialog.OverwritePrompt = true;
pSaveFileDialog.Filter = "ArcMap文档(*.mxd)|*.mxd|ArcMap模板(*.mxt)|*.mxt";
if (pSaveFileDialog.ShowDialog() == DialogResult.OK)
{
    IMapDocument pMapDocument = new MapDocumentClass();
    pMapDocument.New(pSaveFileDialog.FileName);
    pMapDocument.ReplaceContents(axMapControl.Map as IMxdContents);
    pMapDocument.Save();
    MessageBox.Show("保存地图文档成功!");
}

1.3.3 打开数据库

首先要理解工作空间的概念,一个数据库就是一个工作空间,工作空间内存储数据集,数据集内部存储要素类、关系类、栅格数据等。

img img

将打开数据库内部数据封装成一个方法(在BasicClass):

public static void AddLayersFromDataset(IWorkspace pWorkspace, AxMapControl axMapControl)
{
    try
    {
        IEnumDataset pEnumDataset = pWorkspace.get_Datasets(esriDatasetType.esriDTAny);
        pEnumDataset.Reset();
        IDataset pDataset = pEnumDataset.Next();
        while (pDataset != null)
        {
            switch (pDataset.Type)
            {
                case esriDatasetType.esriDTFeatureClass:    //要素类
                    {
                        IFeatureWorkspace pFeatureWorkspace = (IFeatureWorkspace)pWorkspace;
                        IFeatureClass pFeaCls = pFeatureWorkspace.OpenFeatureClass(pDataset.Name);
                        IFeatureLayer pFeaLyr = new FeatureLayerClass();
                        pFeaLyr.FeatureClass = pFeaCls;
                        axMapControl.Map.AddLayer(pFeaLyr);
                    }
                    break;
                case esriDatasetType.esriDTFeatureDataset:  //要素集
                    {
                        IFeatureWorkspace pFeatureWorkspace = (IFeatureWorkspace)pWorkspace;
                        IFeatureDataset pFeaDataset = pFeatureWorkspace.OpenFeatureDataset(pDataset.Name);
                        IEnumDataset pEnumFeatureDataset = pFeaDataset.Subsets;
                        pEnumFeatureDataset.Reset();
                        IDataset pDatasetNew = pEnumFeatureDataset.Next();
                        while (pDatasetNew != null)
                        {
                            if (pDatasetNew is IFeatureClass)
                            {
                                IFeatureClass pFeaCls = pFeatureWorkspace.OpenFeatureClass(pDatasetNew.Name);
                                IFeatureLayer pFeaLyr = new FeatureLayerClass();
                                pFeaLyr.FeatureClass = pFeaCls;
                                axMapControl.Map.AddLayer(pFeaLyr);
                            }
                            pDatasetNew = pEnumFeatureDataset.Next();
                        }
                    }
                    break;
                case esriDatasetType.esriDTRasterDataset:   //栅格集
                    MessageBox.Show("还没写哦!");
                    break;
                case esriDatasetType.esriDTTable:           //表格
                    MessageBox.Show("还没写哦!");
                    break;
                case esriDatasetType.esriDTTopology:        //拓扑
                    MessageBox.Show("还没写哦!");
                    break;
                default:
                    MessageBox.Show("还没写哦!");
                    break;
            }
            pDataset = pEnumDataset.Next();
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

1.4 地图浏览

image-20200622144254091

平移:在菜单点击事件修改axMapControl.MousePointer属性,在axMapControl的鼠标按下事件内调用axMapControl.Pan();

缩放:自定义封装Tool类实现ITool和ICommad接口

历史视图:自定义封装Command类实现ICommand接口

书签:调用ArcGIS组件类库

注:ICommand实现命令,不需要与axMapControl交互;ITool需要与axMapControl交互,绑定了axMapControl的键盘、鼠标事件。

1.4.1 ICommand接口实现

以“前一视图”为例,新建一个类继承ICommand(ESRI.ArcGIS.SystemUI)接口,显式实现接口,OnCreate(object Hook)传入axMapControl控件Object属性,OnClick()实现功能,历史视图是通过IActiveView.ExtentStack视图堆栈实现的。

public void OnCreate(object Hook)
{
    hookHelper = new HookHelperClass();
    hookHelper.Hook = Hook;
    extentStack = hookHelper.ActiveView.ExtentStack;
    if (hookHelper.ActiveView == null)
        hookHelper = null;
}

public void OnClick()
{
    if (extentStack.CanUndo())
        extentStack.Undo();
    else
        enabled = false;
}

//调用
ICommand cmd = new ExtentBackCommand();
cmd.OnCreate(axMapControl.Object);
cmd.OnClick();

1.4.2 ITool接口实现

注:可以配合ICommand使用

放大功能

//鼠标指针样式
public int Cursor
{
    get
    {
        ISystemMouseCursor pMouse = new SystemMouseCursorClass();
        pMouse.Load(esriSystemMouseCursor.esriSystemMouseCursorZoomIn);
        return pMouse.Cursor;
    }
}

public void OnMouseDown(int button, int shift, int x, int y)
{
    if (button == 2) return;
    //框选
    IEnvelope pEnv = mapControl.TrackRectangle();
    //点选
    if (pEnv.IsEmpty || pEnv.Width == 0 || pEnv.Height == 0)
    {
        pEnv = mapControl.Extent;
        pEnv.Expand(0.5, 0.5, true);
    }
    mapControl.Extent = pEnv;
    mapControl.Refresh();
}

//调用
ICommand tool = new MapZoomInTool();
tool.OnCreate(axMapControl.Object);
axMapControl.CurrentTool = tool as ITool;

1.4.3 组件库类调用

"ControlXXXXX"(ESRI.ArcGIS.Controls)形式的类

1.4.4 视图同步

用IDisplayTransformation装axMapControl.Extent视图,用IObjectCopy拷贝地图

IActiveView pActiveView = (IActiveView)axPageLayoutControl.ActiveView.FocusMap;
IDisplayTransformation displayTransformation = pActiveView.ScreenDisplay.DisplayTransformation;
displayTransformation.VisibleBounds = axMapControl.Extent;
IObjectCopy pObjectCopy = new ObjectCopyClass();
object copyMap = pObjectCopy.Copy(axMapControl.Map);//复制地图到copiedMap中
object copyToMap = axPageLayoutControl.ActiveView.FocusMap;
pObjectCopy.Overwrite(copyMap, ref copyToMap); //复制地图

1.4.5 鼠标坐标

响应axMapControl_OnMouseMove事件

sMapUnits = BasicClass.GetMapUnit(axMapControl.Map.MapUnits);
statusBarLblCoor.Text = string.Format("{0:#.###} {1:#.###} {2}", e.mapX, e.mapY, sMapUnits);

其中地图单位获取(封装在BasicClass内)

public static string GetMapUnit(esriUnits mapUnit)
{
    string sMapUnit = string.Empty;
    switch (mapUnit)
    {
        case esriUnits.esriCentimeters:
            sMapUnit = "厘米";
            break;
        case esriUnits.esriDecimalDegrees:
            sMapUnit = "十进制";
            break;
        case esriUnits.esriDecimeters:
            sMapUnit = "分米";
            break;
        case esriUnits.esriFeet:
            sMapUnit = "尺";
            break;
        case esriUnits.esriInches:
            sMapUnit = "英寸";
            break;
        case esriUnits.esriKilometers:
            sMapUnit = "千米";
            break;
        case esriUnits.esriMeters:
            sMapUnit = "米";
            break;
        case esriUnits.esriMiles:
            sMapUnit = "英里";
            break;
        case esriUnits.esriMillimeters:
            sMapUnit = "毫米";
            break;
        case esriUnits.esriNauticalMiles:
            sMapUnit = "海里";
            break;
        case esriUnits.esriPoints:
            sMapUnit = "点";
            break;
        case esriUnits.esriUnitsLast:
            sMapUnit = "UnitsLast";
            break;
        case esriUnits.esriUnknownUnits:
            sMapUnit = "未知单位";
            break;
        case esriUnits.esriYards:
            sMapUnit = "码";
            break;
        default:
            sMapUnit = "未知单位";
            break;
    }
    return sMapUnit;
}

1.4.6 比例尺

实时显示当前比例尺

响应axMapControl_OnAfterScreenDraw事件:menuCboMapScale.Text = string.Format("1:{0:#}", axMapControl.MapScale);

手动输入比例尺

键盘代码KeyValue请参考:CSDN:C# KeyValue列表

响应menuCboMapScale_KeyPress事件

if (e.KeyChar == 13)    //Enter
{
    bool isColon = menuCboMapScale.Text.Contains(":");
    if (isColon)
    {
        string[] strArray = menuCboMapScale.Text.Split(':');
        axMapControl.MapScale = double.Parse(strArray[1]);
    }
    else
        axMapControl.MapScale = double.Parse(menuCboMapScale.Text);
    axMapControl.Refresh();
}

国家标准比例尺

1:100,1:500,1:1000,1:2000,1:5000,1:1万,1:2万,1:5万,1:10万,1:25万,1:50万,1:100万

响应menuCboMapScale_SelectedIndexChanged事件

string sMapScale = menuCboMapScale.SelectedItem.ToString();
string[] sArray = sMapScale.Split(':');//冒号分隔
axMapControl.MapScale = double.Parse(sArray[1].Trim(','));//去除逗号
axMapControl.Refresh();

1.5 图层管理

1.5.1 右键菜单

添加contextMenuStrip控件,在axTOCControl的OnMouseDown事件内写代码

if (e.button == 2)//右键
{
    esriTOCControlItem item = esriTOCControlItem.esriTOCControlItemNone;
    IBasicMap pBasicMap = null;
    object unk = null;
    object data = null;
    axTOCControl.HitTest(e.x, e.y, ref item, ref pBasicMap, ref pLyr, ref unk, ref data);
    if (item == esriTOCControlItem.esriTOCControlItemLayer)
    {
        if (pLyr is IFeatureLayer)  //矢量图层
        {
            pFeaLyr = pLyr as IFeatureLayer;
            btnAttributeTable.Visible = true;
            btnLayerSelected.Visible = true;
            btnLayerSelectable.Visible = true;
            btnLayerUnSelectable.Visible = true;
            btnLayerOutput.Visible = true;
            btnLayerSelectable.Enabled = !pFeaLyr.Selectable;
            btnLayerUnSelectable.Enabled = pFeaLyr.Selectable;
            btnLayerSelected.Enabled = pFeaLyr.Selectable;
        }
        else  //栅格图层
        {
            btnAttributeTable.Visible = false;
            btnLayerSelected.Visible = false;
            btnLayerSelectable.Visible = false;
            btnLayerUnSelectable.Visible = false;
            btnLayerOutput.Visible = false;
        }
        contextMenu.Show(Control.MousePosition);
    }
}

右键菜单

1.5.2 图层定位

将图层的“兴趣区”赋值给地图控件的视图属性,axMapControl.Extent = pFeaLyr.AreaOfInterest;

1.6 交互优化

软件没有数据时,一些功能是禁用的。

响应axMapControl_OnAfterScreenDraw事件:

//1 激活相关控件
//1.1 地图浏览
bool isData = false;//存在数据?
isData = axMapControl.LayerCount > 0 ? true : false;
barMapBrowse.Enabled = isData;
//1.2 选择查询
barSelect.Enabled = isData;
//1.3 空间编辑
barEditor.Enabled = isData;
//1.4 历史视图
bool canUndo = axMapControl.ActiveView.ExtentStack.CanUndo();
btnExtentBack.Enabled = canUndo;
bool canRedo = axMapControl.ActiveView.ExtentStack.CanRedo();
btnExtentForward.Enabled = canRedo;

主界面图标,响应FormMain_Load

//添加图标
IntPtr Hicon = Properties.Resources.GenericGlobeLarge_B_16.GetHicon();
Icon newIcon = Icon.FromHandle(Hicon);
this.Icon = newIcon;

源码链接:组件GIS

原文地址:https://www.cnblogs.com/liuwenzhen/p/13095610.html