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(不支持快捷键);每一个菜单项图标标来源于项目资源文件。
1.3 文件管理
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 打开数据库
首先要理解工作空间的概念,一个数据库就是一个工作空间,工作空间内存储数据集,数据集内部存储要素类、关系类、栅格数据等。
将打开数据库内部数据封装成一个方法(在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 地图浏览
平移:在菜单点击事件修改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