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