使用C#配合ArcGIS Engine進(jìn)行地理信息系統(tǒng)開發(fā)
簡(jiǎn)單的地圖讀取、展示
終于到暑假了。。。開始認(rèn)真整理整理相關(guān)學(xué)習(xí)的心得體會(huì)咯~
先把很久之前挖的關(guān)于C# 二次開發(fā)的坑給填上好了~ 這次先計(jì)劃用一個(gè)月把C# ArcEngine 10.0相關(guān)開發(fā)的學(xué)習(xí)心得給發(fā)布出來好啦~
第一部分就是最簡(jiǎn)單的helloworld了:掌握使用控件創(chuàng)建簡(jiǎn)單的GIS應(yīng)用程序~
(前期相關(guān)環(huán)境配置略掉~請(qǐng)自行百度~)
首先打開VS2010,,通過(文件--新建--項(xiàng)目--Windos窗體應(yīng)用程序) ,我們新建一個(gè)名叫“MyHelloWorld”的Windows 窗體應(yīng)用程序。然后就要開始往里面填控件了:
在 VS 的工具箱中找到到和 ArcGIS Engine 相關(guān)的控件 ,在這里我們使用AxTOCControl(目錄控件),AxLicenseControl (許可控件),以及MapControl,在這里MapControl對(duì)應(yīng)于 ArcMap 中的數(shù)據(jù)視圖,它封裝了Map 對(duì)象,并提供了額外的屬性,方法,事件等。是我們?cè)诮觼硐碌囊幌盗虚_發(fā)中必不可少的一環(huán)。
將3個(gè)控件排列一下后,效果如下圖所示:

注意:
1.其中AxLicenseControl 控件是整個(gè)Arcengine開發(fā)中必須的許可控件,如果沒有它或者沒有ArcEngine的Lisence許可的話,我們是無法調(diào)用任何GIS功能的。
2.將三個(gè)控件拖入窗體后,我們會(huì)發(fā)現(xiàn)系統(tǒng)自動(dòng)導(dǎo)入了相關(guān)引用,但無論是系統(tǒng)自己導(dǎo)入的引用還是我們手動(dòng)導(dǎo)入的,請(qǐng)注意將引用屬性中的“復(fù)制本地”設(shè)置為False,否則可能會(huì)產(chǎn)生無法運(yùn)行代碼的情況。
控件設(shè)置好之后,我們打開Program.cs,在系統(tǒng)的入口處添加這樣一行代碼:
ESRI.ArcGIS.RuntimeManager.Bind(ESRI.ArcGIS.ProductCode.EngineOrDesktop);
這主要是針對(duì)Arcgis10.0的變化而設(shè)置的,添加后的代碼如下:
namespace MyHelloWorld
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
ESRI.ArcGIS.RuntimeManager.Bind(ESRI.ArcGIS.ProductCode.EngineOrDesktop);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
接下來,我們就可以通過設(shè)置編輯ToolbarControl的屬性,來給它添加上我們需要的工具了,同時(shí)要記得在ToolBar控件和axTOCCControl1控件的屬性設(shè)置中,將ToolBar的Buddy選項(xiàng)設(shè)置為axTOCCControl1,這樣就可以將二者進(jìn)行聯(lián)動(dòng)。
在ToolbarControl的屬性設(shè)置中,我們可以通右鍵——屬性——Item來給Toolbar控件設(shè)置我們需要的工具,在這里我選擇了一些常用的工具:保存、移動(dòng)、撤銷、放大、縮小等等,過程如下圖所示:

全部設(shè)置后之后,第一章的內(nèi)容就基本結(jié)束了,將程序調(diào)試后,最終效果如下圖,一個(gè)最簡(jiǎn)單的GIS桌面程序就出來啦~~

打開地圖文檔、鷹眼圖的制作
首先是制作一個(gè)按鈕來負(fù)責(zé)打開地圖文檔:
在toolbox中選擇Button控件拖入我們的Form中,接下來在該button的Cilck事件中調(diào)用 OpenFileDialog類獲取文件路徑后,
將文件路徑調(diào)用到axMapControl1.LoadMxFile(path)中就可以打開MXD文檔了。
private void button1_Click(object sender, EventArgs e)
{
OpenFileDialog OpenMXD = new OpenFileDialog();
OpenMXD.Title = "打開地圖";
OpenMXD.InitialDirectory = "E:";
OpenMXD.Filter = "Map Documents (*.mxd)|*.mxd";
if (OpenMXD.ShowDialog() == DialogResult.OK)
{
string MxdPath = OpenMXD.FileName;
axMapControl1.LoadMxFile(MxdPath);
<span style="white-space:pre"> </span>}
}
我們可以通過相同的方法打開shape文件,但是這里要注意:
axMapControl1.AddShapeFile()方法中,并不是像LoadMx一樣直接輸入文件路徑就行,而是AddShapeFile(filePath, fileName),因此我們要先編寫一個(gè)函數(shù)將文件路徑的字符串進(jìn)行分割:
private void button2_Click(object sender, EventArgs e)
{
{
string[] S = OpenShapeFile();
try
{
axMapControl1.AddShapeFile(S[0], S[1]);
}
catch
{
MessageBox.Show("請(qǐng)至少選擇一個(gè)shape文件", "ERROR");
}
}
}
public string[] OpenShapeFile()
{
string[] ShpFile = new string[2];
OpenFileDialog OpenShpFile = new OpenFileDialog();
OpenShpFile.Title = "打開Shape文件";
OpenShpFile.InitialDirectory = "E:";
OpenShpFile.Filter = "Shape文件(*.shp)|*.shp";
if (OpenShpFile.ShowDialog() == DialogResult.OK)
{
string ShapPath = OpenShpFile.FileName;
//利用"\\"將文件路徑分成兩部分
int Position = ShapPath.LastIndexOf("\\");
string FilePath = ShapPath.Substring(0, Position);
string ShpName = ShapPath.Substring(Position + 1);
ShpFile[0] = FilePath;
ShpFile[1] = ShpName;
}
return ShpFile;
}
運(yùn)行后結(jié)果如下:

這部分完成后,接下來是鷹眼圖的制作~:
鷹眼圖的操作主要分為兩個(gè)部分,當(dāng)在主控件中重新加載一幅圖的時(shí)候,另外一個(gè)控件的圖也發(fā)生相應(yīng)的變化, 大致思路是在獲得你在打開主地圖后,向鷹眼圖(MapControl2)中添加相同的圖層,并不斷更新你在主地圖的當(dāng)前范圍,再在鷹眼圖的對(duì)應(yīng)區(qū)域中繪制一個(gè)紅框表示對(duì)應(yīng)范圍。
這里主要使用了IEnvelope和IPoint接口,用來獲取鼠標(biāo)所在坐標(biāo)、繪制表示范圍的紅框,具體用法可以參考這里~
我們?cè)趂orm中拖入第二個(gè)地圖控件axMapControl2,用它作為axMapControl1的鷹眼圖進(jìn)行表示。
這里首先對(duì)MapControl1的OnMapReplaced事件和OnExtentUpdated事件進(jìn)行編寫,讓我們獲得MapControl1的地圖范圍更新,并向MapControl2添加圖層、繪制矩形:
private void axMapControl1_OnExtentUpdated(object sender, ESRI.ArcGIS.Controls.IMapControlEvents2_OnExtentUpdatedEvent e)
{
//設(shè)置一個(gè)新的外接矩形
IEnvelope pEnvelope = (IEnvelope)e.newEnvelope;
IGraphicsContainer pGraphicsContainer = axMapControl2.Map as IGraphicsContainer;
IActiveView pActiveView = pGraphicsContainer as IActiveView;
//在繪制前,清除axMapControl2中的任何圖形元素
pGraphicsContainer.DeleteAllElements();
IRectangleElement pRectangleEle = new RectangleElementClass();
IElement pElement = pRectangleEle as IElement;
pElement.Geometry = pEnvelope;
//設(shè)置鷹眼圖中的紅線框
IRgbColor pColor = new RgbColorClass();
pColor.Red = 255;
pColor.Green = 0;
pColor.Blue = 0;
pColor.Transparency = 255;
//產(chǎn)生一個(gè)線符號(hào)對(duì)象
ILineSymbol pOutline = new SimpleLineSymbolClass();
pOutline.Width = 3;
pOutline.Color = pColor;
//設(shè)置顏色屬性
pColor = new RgbColorClass();
pColor.Red = 255;
pColor.Green = 0;
pColor.Blue = 0;
pColor.Transparency = 0;
//設(shè)置填充符號(hào)的屬性
IFillSymbol pFillSymbol = new SimpleFillSymbolClass();
pFillSymbol.Color = pColor;
pFillSymbol.Outline = pOutline;
IFillShapeElement pFillShapeEle = pElement as IFillShapeElement;
pFillShapeEle.Symbol = pFillSymbol;
pGraphicsContainer.AddElement((IElement)pFillShapeEle, 0);
pActiveView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, null, null);
//將地圖范圍顯示在StripStatus中
IPoint ll, Ur;
ll = axMapControl1.Extent.LowerLeft;
Ur = axMapControl1.Extent.LowerRight;
toolStripStatusLabel3.Text = "(" + Convert.ToString(ll.X) + "," + Convert.ToString(ll.Y) + ")";
}
private void axMapControl1_OnMapReplaced(object sender, ESRI.ArcGIS.Controls.IMapControlEvents2_OnMapReplacedEvent e)
{ //向MapControl2添加圖層
if (axMapControl1.LayerCount > 0)
{
axMapControl2.Map = new MapClass();
for (int i = 0; i <= axMapControl1.Map.LayerCount - 1; i++)
{
axMapControl2.AddLayer(axMapControl1.get_Layer(i));
}
axMapControl2.Extent = axMapControl1.Extent;
axMapControl2.Refresh();
}
}
接下來就是對(duì)MapControl2控件的On_MouseDown 和 On_MouseMove事件進(jìn)行編寫,這樣可以讓我們通過拖動(dòng)鷹眼圖上的紅框反向操作MapControl1中的地圖位置:
private void axMapControl2_OnMouseMove(object sender, ESRI.ArcGIS.Controls.IMapControlEvents2_OnMouseMoveEvent e)
{
if (e.button == 1)
{
IPoint pPoint = new PointClass();
pPoint.PutCoords(e.mapX, e.mapY);
axMapControl1.CenterAt(pPoint);
axMapControl1.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeography,
null, null);
}
}
private void axMapControl2_OnMouseDown(object sender, ESRI.ArcGIS.Controls.IMapControlEvents2_OnMouseDownEvent e)
{
if (axMapControl2.Map.LayerCount > 0)
{
if (e.button == 1)
{
IPoint pPoint = new PointClass(); //將點(diǎn)擊位置的坐標(biāo)轉(zhuǎn)換后設(shè)為MapControl1的中心
pPoint.PutCoords(e.mapX, e.mapY);
axMapControl1.CenterAt(pPoint);
axMapControl1.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeography, null, null);
}
else if (e.button == 2)
{
IEnvelope pEnv = axMapControl2.TrackRectangle();
axMapControl1.Extent = pEnv;
axMapControl1.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeography, null, null);
}
}
}
最后在Form左下角再添加一個(gè)statusStrip控件,就可以實(shí)時(shí)顯示當(dāng)前圖幅的范圍了~
最終效果如下:

屬性表的訪問與顯示
這里主要是訪問并顯示shapefile的屬性表~
大致思路如下:新建一個(gè)Form用來獲取選中要素的屬性表,而在初始界面右鍵點(diǎn)擊對(duì)應(yīng)的矢量要素后,便打開新form將要素屬性表展示出來。
下面就開始咯~
首先要添加ESRI.ArcGIS.Controls、Geodatabase的引用,更新命名空間;
然后我們添加一個(gè)用于顯示屬性表內(nèi)容新的 Form 窗體,在這個(gè)新的窗體上添加 dataGridView 控件,并添加Column。

在Form2中,我們先將可能獲得的屬性表數(shù)據(jù)類型進(jìn)行預(yù)定義:
public static string ParseFieldType(esriFieldType fieldType)//將EsriType 轉(zhuǎn)換為String
{
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";
}
}
然后就是獲取shpaefile的屬性表了,這里我們主要使用 IField、IFeatureCursor、IFeature 這三個(gè)接口來達(dá)成目標(biāo):
接口說明如下:
- IField 接口:用于獲取要素表。
- IFeature 接口:用來接收查詢出來的要素。
- IFeatureCursor 接口:通過Search進(jìn)行查詢,可以將結(jié)果保存在這里,從而利用NextFeature方法,遍歷所有要素。
代碼如下:
public void Opentable()
{
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(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();
}
}
搞定~接下來就是在初始界面選定要素后跳轉(zhuǎn)界面顯示屬性表了~
先在form1中進(jìn)行預(yù)定義:
IFeatureLayer pFeatureLayer = null; public IFeatureLayer pGlobalFeatureLayer; //定義全局變量 public ILayer player;
因?yàn)闆Q定在右擊鼠標(biāo)時(shí)顯示選項(xiàng),在Form1窗體中添加contextMenuStrip控件,添加選項(xiàng)”顯示屬性表“,在click事件中打開新form:
Form2 Ft = new Form2(player as IFeatureLayer);
Ft.Show();
然后就保證右鍵點(diǎn)擊相關(guān)圖層要素后能夠成功打開對(duì)應(yīng)屬性表啦,這里主要用了TOCControl的 HitTest()方法:
publicvoid HitTest ( int X, int Y, ref esriTOCControlItem ItemType, ref IBasicMapBasicMap, ref ILayer Layer, ref object Unk, ref object Data );
其中
- X,Y:鼠標(biāo)點(diǎn)擊的坐標(biāo);
- ITemType:esriTOCControlItem枚舉常量
- BasicMap:綁定MapControl的IBasicMap接口
- Layer:被點(diǎn)擊的圖層
- Unk:TOCControl的LegendGroup對(duì)象
- Data:LegendClass在LegendGroup中的Index。
在TOCControl控件的 OnMouseDown 事件下添加如下代碼即可~:
if (axMapControl1.LayerCount > 0)
{
esriTOCControlItem pItem = new esriTOCControlItem();
pGlobalFeatureLayer = new FeatureLayerClass();
IBasicMap pBasicMap = new MapClass();
object pOther = new object();
object pIndex = new object();
axTOCControl1.HitTest(e.x, e.y, ref pItem, ref pBasicMap, ref player, ref pOther, ref pIndex);
}
if (e.button == 2)
{
contextMenuStrip1.Show(axTOCControl1, e.x, e.y);
}
大功告成~~
運(yùn)行結(jié)果如下:
右擊顯示屬性表:

點(diǎn)擊后出現(xiàn)屬性表~~~:

- C#實(shí)現(xiàn)的Socket服務(wù)器端、客戶端代碼分享
- 在C#中對(duì)TCP客戶端的狀態(tài)封裝詳解
- C#用Activex實(shí)現(xiàn)Web客戶端讀取RFID功能的代碼
- c# socket編程udp客戶端實(shí)現(xiàn)代碼分享
- 獲取客戶端IP地址c#/vb.net各自實(shí)現(xiàn)代碼
- 分享用于操作FTP的客戶端C#類
- C#如何取硬件標(biāo)志
- C#實(shí)現(xiàn)獲取運(yùn)行平臺(tái)系統(tǒng)信息的方法
- C# 當(dāng)前系統(tǒng)時(shí)間獲取及時(shí)間格式詳解
- 使用C#獲取系統(tǒng)特殊文件夾路徑的解決方法
- C#獲取系統(tǒng)版本信息方法
- C# 獲取系統(tǒng)進(jìn)程的用戶名
- C#編程獲取客戶端計(jì)算機(jī)硬件及系統(tǒng)信息功能示例
相關(guān)文章
Python djanjo之csrf防跨站攻擊實(shí)驗(yàn)過程
csrf攻擊,即cross site request forgery跨站(域名)請(qǐng)求偽造,這里的forgery就是偽造的意思。這篇文章主要給大家介紹了關(guān)于Python djanjo之csrf防跨站攻擊的相關(guān)資料,需要的朋友可以參考下2021-05-05
Python IDE PyCharm的基本快捷鍵和配置簡(jiǎn)介
這篇文章主要介紹了Python IDE PyCharm的基本快捷鍵和配置簡(jiǎn)介,PyCharm為一個(gè)收費(fèi)的軟件,需要的朋友可以參考下2015-11-11
Python導(dǎo)入txt數(shù)據(jù)到mysql的方法
這篇文章主要介紹了Python導(dǎo)入txt數(shù)據(jù)到mysql的方法,涉及Python操作txt文件及mysql數(shù)據(jù)庫的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-04-04
利用python實(shí)現(xiàn)flappy bird 游戲(完整代碼)
python 中 pygame模塊能讓我們很方便的編寫游戲,16年我用python 仿制了flappy bird 游戲,下面是游戲的完整代碼以及素材,分享給大家2021-11-11
python numpy 一維數(shù)組轉(zhuǎn)變?yōu)槎嗑S數(shù)組的實(shí)例
今天小編就為大家分享一篇python numpy 一維數(shù)組轉(zhuǎn)變?yōu)槎嗑S數(shù)組的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-07-07
對(duì)pandas中Series的map函數(shù)詳解
今天小編就為大家分享一篇對(duì)pandas中Series的map函數(shù)詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-07-07
python導(dǎo)出requirements.txt的幾種方法以及環(huán)境配置詳細(xì)流程
這篇文章主要給大家介紹了關(guān)于python導(dǎo)出requirements.txt的幾種方法以及環(huán)境配置詳細(xì)流程,requirements.txt 文件是一個(gè)文本文件,用于列出你的Python項(xiàng)目所依賴的軟件包及其版本,需要的朋友可以參考下2023-11-11

