先看一下GeoDatabase核心結構模型圖:

1 工作空間工廠WorkspaceFactory對象
WorkspaceFactory是GeoDatabase的入口,是一個抽象類,擁有很多子類,例如SdeWorkspaceFactory, AccessWorkspaceFactory, ShapfileWorkspaceFactory CadWorkspaceFactory等
IWorkspaceFactory接口定義了所有工作空間對象的一般屬性和方法
public IWorkspaceName Create (string parentDirectory,string Name,IPropertySet ConnectionProperties,int hWnd);用於產生一個新的工作空間名稱對象,前兩個參數是數據庫的路徑和名稱,第三個參數是一個屬性集(properset)對象。
public IWorkspace Open ( IPropertySet ConnectionProperties,int hWnd);打開一個已經存在的工作空間像SDE數據庫等;
public IWorkspace OpenFromFile (string fileName,int hWnd);打開一個文件類型的數據
2 工作空間WorkSpace對象
Workspace在邏輯上是一個包含空間數據集和非空間數據集的數據容器,數據包括要素類、柵格數據集、表等對象
Workspace對象主要的一些接口:
1 IWorkspace接口:定義了一個工作空間最普通的屬性和方法。
2 IFeatureWorkspace接口
這個接口主要用於管理要素的數據集,如表(Table)、對象類(ObjectClass)、要素類(FeatureClass)、要素數據集(FeatureDataset)和關系類(RelationshipClass)等。
主要的成員:

public IFeatureClass OpenFeatureClass ( string Name) 打開一個已經存在的要素類,無論這個要素類是在工作空間還是在一個要素數據集中
public IFeatureDataset OpenFeatureDataset (string Name);打開一個已經存在的要素數據集
public ITable OpenTable (string Name);打開一個已經存在的表;
3 RasterWorkspace對象
主要實現了IRasterWorkspace接口
public IRasterDataset OpenRasterDataset ( string Name);
4 屬性集Propertyset對象
Propertyset對象是一個專門用於設置屬性的對象,它是一種name-value對應的集合,類似於Hash表。屬性名必須是字符串,屬性值可以是字符串、數值或日期也可以是一個對象
5 DataSet數據集對象
Dataset對象可分為兩大類:Table和GeoDataset,GeoDataset是一個抽象類,代表了擁有空間屬性的數據集,包括FeatureDataset、要素類FeatureClass、TIN和柵格數據集RasterDataset。
6 FeatureDataset對象
實現的主要接口:
1 IFeatureDataset接口
public IEnumDataset Subsets {get;}:Datasets contained within this dataset.
2 IFeatureClassContainer接口
用於管理要素數據集里面的要素類,該接口的ClassByName和Class(index)等屬性可以用來獲取數據集中的特定的要素類(這里很奇怪在幫助文檔中只有屬性沒有方法但點進去卻是一個方法Ok你大概不理解我說的)
public IFeatureClass get_Class (int ClassIndex);
public IFeatureClass get_ClassByID (int ID);
public IFeatureClass get_ClassByName (string Name);
接下來舉幾個加載各種數據的例子
1 加載Shapefiles文件
OpenFileDialog dlg=new OpenFileDialog();
dlg.Title="打開shapefile文件";
dlg.Filter="(*.shp)|*.shp";
dlg.ShowDialog();
string filename=dlg.FileName;
int index=filename.LastIndexOf(@"\");
string path=filename.Substring(0,index);
string name=filename.Substring(index+1);
IWorkspaceFactory pWsFactory = new ShapefileWorkspaceFactoryClass();
IFeatureWorkspace pWorkSpace = pWsFactory.OpenFromFile(path, 0) as IFeatureWorkspace;
IFeatureClass pFeatureClass = pWorkSpace.OpenFeatureClass(name);
IFeatureLayer pFeatureLayer = new FeatureLayerClass();
pFeatureLayer.Name = pFeatureClass.AliasName;
pFeatureLayer.FeatureClass = pFeatureClass;
axMapControl1.Map.AddLayer(pFeatureLayer);
axMapControl1.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, null, null);
2.加載柵格數據
OpenFileDialog dlg = new OpenFileDialog();
dlg.Title = "打開Raster文件";
dlg.Filter = " Layer File(*.lyr)|*.jpg;*.bmp;*.tiff ";
dlg.ShowDialog();
string filename = dlg.FileName;
int index = filename.LastIndexOf(@"\");
string path = filename.Substring(0, index);
string name = filename.Substring(index + 1);
IWorkspaceFactory pWsFactory =new RasterWorkspaceFactoryClass();
IRasterWorkspace pRasterWorkspace = pWsFactory.OpenFromFile(path, 0) as IRasterWorkspace;
IRasterDataset pRasterDataset = pRasterWorkspace.OpenRasterDataset(name);
IRasterLayer pRasterLayer = new RasterLayerClass();
pRasterLayer.CreateFromDataset(pRasterDataset);
axMapControl1.Map.AddLayer(pRasterLayer);
axMapControl1.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, null, null);
3 加載CAD數據
OpenFileDialog dlg = new OpenFileDialog();
dlg.Title = "打開CAD文件";
dlg.Filter = " CAD(*.dwg)|*.dwg|All Files(*.*)|*.* ";
dlg.ShowDialog();
string filename = dlg.FileName;
int index = filename.LastIndexOf(@"\");
string path = filename.Substring(0, index);
string name = filename.Substring(index + 1);
IWorkspaceFactory pWsFactory = new CadWorkspaceFactoryClass();
IFeatureWorkspace pFeatureWorkspace = pWsFactory.OpenFromFile(path, 0) as IFeatureWorkspace;
IFeatureDataset pFeatureDataset = pFeatureWorkspace.OpenFeatureDataset(name);
IFeatureClassContainer pFCContainer = pFeatureDataset as IFeatureClassContainer;
for (int i = 0; i < pFCContainer.ClassCount; i++)
{
IFeatureClass pFeatureClass = pFCContainer.get_Class(i);
if (pFeatureClass.FeatureType == esriFeatureType.esriFTCoverageAnnotation)
{
IFeatureLayer pFeatureLayer = new CadAnnotationLayerClass();
}
else
{
IFeatureLayer pFeatureLayer = new FeatureLayerClass();
pFeatureLayer.FeatureClass = pFeatureClass;
pFeatureLayer.Name = pFeatureClass.AliasName;
axMapControl1.Map.AddLayer(pFeatureLayer);
}
axMapControl1.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, null, null);
4 加載PersonGeodatabase數據
OpenFileDialog dlg = new OpenFileDialog();
dlg.Title = "打開Geodatabase文件";
dlg.Filter = " Personal Geodatabase(*.mdb)|*.mdb|All Files(*.*)|*.* ";
dlg.ShowDialog();
string path = dlg.FileName;
IWorkspaceFactory pAccessWorkspaceFactory;
IFeatureWorkspace pFeatureWorkspace;
IFeatureLayer pFeatureLayer;
IFeatureDataset pFeatureDataset;
pAccessWorkspaceFactory = new AccessWorkspaceFactoryClass();
IWorkspace pWorkspace = pAccessWorkspaceFactory.OpenFromFile(path, 0);
IEnumDataset pEnumDataset = pWorkspace.get_Datasets(ESRI.ArcGIS.Geodatabase.esriDatasetType.esriDTAny);
pEnumDataset.Reset();
IDataset pDataset = pEnumDataset.Next();
if (pDataset is IFeatureDataset)
{
pFeatureWorkspace = (IFeatureWorkspace)pAccessWorkspaceFactory.OpenFromFile(path, 0);
pFeatureDataset = pFeatureWorkspace.OpenFeatureDataset(pDataset.Name);
IEnumDataset pEnumDataset1 = pFeatureDataset.Subsets;
pEnumDataset1.Reset();
IDataset pDataset1 = pEnumDataset1.Next();
if (pDataset1 is IFeatureClass)
{
pFeatureLayer = new FeatureLayerClass();
pFeatureLayer.FeatureClass = pFeatureWorkspace.OpenFeatureClass(pDataset1.Name);
pFeatureLayer.Name = pFeatureLayer.FeatureClass.AliasName;
axMapControl1.Map.AddLayer(pFeatureLayer);
axMapControl1.ActiveView.Refresh();
}
}
else
{
pFeatureWorkspace = (IFeatureWorkspace)pWorkspace;
pFeatureLayer = new FeatureLayerClass();
pFeatureLayer.FeatureClass = pFeatureWorkspace.OpenFeatureClass(pDataset.Name);
pFeatureLayer.Name = pFeatureLayer.FeatureClass.AliasName;
axMapControl1.Map.AddLayer(pFeatureLayer);
axMapControl1.ActiveView.Refresh();
}
1、加載個人數據庫
個人數據庫是保存在Access中的數據庫。其加載方式有兩種:通過名字和通過屬性加載(也許不只這兩種,AE中實現同一功能可以有多種方式)。
A、通過設置屬性加載個人數據庫。
首先通過IPropertySet接口定義要連接數據庫的一些相關屬性,在個人數據庫中為數據庫的路徑,例如:
IPropertySet Propset = new PropertySetClass();
Propset.SetProperty("DATABASE",@"D:\test\Ao\data\sh\MapData.mdb" );
當定義完屬性並設置屬性后就可以進行打開數據庫的操作了,在ArcEngine開發中存在IWorkspaceFactory、 IFeatureWorkspace、IFeatureClass、IFeatureLayer等幾個常用的用於打開和操作數據空間地物的接口。 IWorkspaceFactory是一個用於創建和打開工作空間的接口,它是一個抽象的接口,我們在具體應用時要用對應的工作空間實例化它,如下:
IWorkspaceFactory Fact = new AccessWorkspaceFactoryClass ();
如果我們打開的是SDE數據庫就要用SdeWorkspaceFactoryClass實例化Fact。當我們完成了工作空間的實例化后就可以根據上邊設置的屬性打開對應的Access數據庫了。打開方式如下:
IFeatureWorkspace Workspace = Fact.Open(Propset,0) as IFeatureWorkspace;
打開Access工作空間后接下來的事情是做什么了,很簡單,找到對應的地物類,賦給相應的層,通過MapControl控件添加對應的層,然后刷新地圖。以下為添加某一層的代碼:
IFeatureClass Fcls = Workspace.OpenFeatureClass("District");
IFeatureLayer Fly = new FeatureLayerClass();
Fly.FeatureClass = Fcls;
MapCtr.Map.AddLayer (Fly);
MapCtr.ActiveView.Refresh();
其中District為地物類的名字,MapCtr為AE中MapControl的對象。上邊的通過屬性設置加載數據空間的方式還可以用於SDE 數據庫,在SDE數據庫加載時會介紹。
以下為通過設置屬性加載Access數據庫的完整C#代碼:
public void AddAccessDBByPro()
{
IPropertySet Propset = new PropertySetClass();
Propset.SetProperty("DATABASE",@"D:\test\Ao\data\sh\MapData.mdb" );
IWorkspaceFactory Fact = new AccessWorkspaceFactoryClass ();
IFeatureWorkspace Workspace = Fact.Open(Propset,0) as IFeatureWorkspace;
IFeatureClass Fcls = Workspace.OpenFeatureClass ("District");
IFeatureLayer Fly = new FeatureLayerClass();
Fly.FeatureClass = Fcls;
MapCtr.Map.AddLayer(Fly);
MapCtr.ActiveView.Refresh();
}
B、通過數據庫名字加載個人數據庫
在這我先把完整的代碼寫出來,讓您先跟上邊的代碼做個對比。以下為完整的代碼:
public void AddAccessDBByName()
{
IWorkspaceName pWorkspaceName = new WorkspaceNameClass() ;
pWorkspaceName.WorkspaceFactoryProgID = "esriDataSourcesGDB.AccessWorkspaceFactory";
pWorkspaceName.PathName = @"D:\test\Ao\data\sh\MapData.mdb";
IName n = pWorkspaceName as IName ;
IFeatureWorkspace Workspace = n.Open() as IFeatureWorkspace;
IFeatureClass Fcls = Workspace.OpenFeatureClass ("District");
IFeatureLayer Fly = new FeatureLayerClass();
Fly.FeatureClass = Fcls;
MapCtr.Map.AddLayer (Fly);
MapCtr.ActiveView.Refresh();
}
細心的人已經注意到,打開Access工作空間后接下來的代碼是一樣的,都是找到對應的地物類,賦給相應的層,通過MapControl控件添加 對應的層,然后刷新地圖。現在講解一下上邊的代碼,首先是創建一個個人數據庫工作空間名,在指定工作空間名的ProgID,以確定打開的是什么類型的工作 空間,例如在打開Access個人數據庫時使用的是下邊的代碼:
IWorkspaceName pWorkspaceName = new WorkspaceNameClass() ;
pWorkspaceName.WorkspaceFactoryProgID = "esriDataSourcesGDB.AccessWorkspaceFactory";
pWorkspaceName.PathName = @"D:\test\Ao\data\sh\MapData.mdb";
屬性WorkspaceFactoryProgID可以確保工作空間是AccessWorkspaceFactory,即個人數據庫,同時指定要 打開數據庫的路徑。為了打開數據庫,我們通過AE的類圖可以發現打開工作空間必須使用IName接口(個人認為,不一定正確,可以思考一下看有其他辦法沒 有),所以接着定義IName對象,並把工作空間名轉換成IName類型並賦值給IName對象,然后通過IName對象的Open()方法打開相應的工 作空間,代碼如下:
IName n = pWorkspaceName as IName ;
IFeatureWorkspace Workspace = n.Open () as IFeatureWorkspace;
接下來的事情就是上邊提到。
2、加載SDE數據庫
什么是SDE數據庫?這個問題要詳細地講解將花費大量的時間,但我可以告訴你SDE空間數據庫可以是任何關系數據庫。ESRI公司為了使空間數據 能保存在關系數據庫中,並且能很好的查詢相關的空間屬性而開發的一個中間件,使用SDE能很好的將空間數據保存在關系數據庫中。如Orcale, SQL Server 等。SDE具體細節的了解請查找相關的資料,這里只介紹怎么連接SDE數據庫。SDE數據庫的聯機分為直接連接和通過SDE連接。當服務器的性能比較好的 時候可以采用SDE連接,否則采用直接連接,這樣可以減輕服務器的任務。建議采用直接連接,其實,SDE連接方式和直接連接的方式只是一個屬性參數設置的 問題。跟個人數據庫采用屬性連接的方式一樣,先定義一個屬性對象,然后設置屬性參數,接着定義一個工作空間並用 SdeWorkspaceFactoryClass()實例化它,接着加在加載圖層,至於加載圖層的代碼,與加載個人數據庫中圖層的方法一樣,其實不只加 載這兩種數據類型,加載其他類型的數據時也是采用相同的方法加載圖層,只是工作空間采用不同的實例而已,下邊為完整的對嗎”//”后的為注析:
public void AddSDELayer(bool ChkSdeLinkModle)
{
//定義一個屬性
IPropertySet Propset = new PropertySetClass();
if (ChkSdeLinkModle==true) // 采用SDE連接
{
//設置數據庫服務器名,服務器所在的IP地址
Propset.SetProperty ("SERVER", "192.168.2.41");
//設置SDE的端口,這是安裝時指定的,默認安裝時"port:5151"
Propset.SetProperty ("INSTANCE", "port:5151");
//SDE的用戶名
Propset.SetProperty ("USER", "sa");
//密碼
Propset.SetProperty ("PASSWORD", "sa");
//設置數據庫的名字,只有SQL Server Informix 數據庫才需要設置
Propset.SetProperty ("DATABASE", "sde");
//SDE的版本,在這為默認版本
Propset.SetProperty ("VERSION", "SDE.DEFAULT");
}
else // 直接連接
{
//設置數據庫服務器名,如果是本機可以用"sde:sqlserver:."
Propset.SetProperty ("INSTANCE", "sde:sqlserver:zhpzh");
//SDE的用戶名
Propset.SetProperty ("USER", "sa");
//密碼
Propset.SetProperty ("PASSWORD", "sa");
//設置數據庫的名字,只有SQL Server Informix 數據庫才需要設置
Propset.SetProperty ("DATABASE", "sde");
//SDE的版本,在這為默認版本
Propset.SetProperty ("VERSION", "SDE.DEFAULT");
}
//定義一個工作空間,並實例化為SDE的工作空間
IWorkspaceFactory Fact = new SdeWorkspaceFactoryClass();
//打開SDE工作空間,並轉化為地物工作空間
IFeatureWorkspace Workspace = (IFeatureWorkspace )Fact.Open(Propset,0);
/*定義一個地物類,並打開SDE中的管點地物類,寫的時候一定要寫全.如SDE中有一個管點層,你不能寫成IFeatureClass Fcls = Workspace.OpenFeatureClass ("管點");這樣,一定要寫成下邊的樣子.*/
IFeatureClass Fcls = Workspace.OpenFeatureClass ("sde.dbo.管點");
IFeatureLayer Fly = new FeatureLayerClass ();
Fly.FeatureClass = Fcls;
MapCtr.Map.AddLayer (Fly);
MapCtr.ActiveView.Refresh ();
}
不知道注意到了沒有,直接連接跟SDE連接的最大的不同是直接連接不要設置端口,同時他們的參數設置也不一樣,好好注意參數的設置。
3、加載CAD圖層
CAD圖層的加載可以分為:分圖層加載和整幅圖加載
A、分圖層加載
我們可以把CAD圖分為點、線、面、標注加載到MapControl中,跟加載其他數據一樣,首先要定義一個工作空間,並用 CadWorkspaceFactoryClass()實例化它,當得到了工作空間后就可以打開相應的工作空間,然后再打開指定的層類型。下邊為完整的代 碼:
public void AddCADByLayer()
{
//定義工作空間,並用CadWorkspaceFactoryClass()實例化它
IWorkspaceFactory Fact = new CadWorkspaceFactoryClass();
//打開相應的工作空間,並賦值給要素空間,OpenFromFile()
//中的參數為CAD文件夾的路徑
IFeatureWorkspace Workspace = Fact.OpenFromFile(@"I:\test\",0) as IFeatureWorkspace;
/*打開線要素類,如果要打開點類型的要素,需要把下邊的代碼該成:
IFeatureClass Fcls = Workspace.OpenFeatureClass ("modle.dwg:point");
由此可見modle.dwg為CAD圖的名字,后邊加上要打開的要素類的類型,中間用冒號隔開,大家可以想想多邊形和標注是怎么打開的。 */
IFeatureClass Fcls = Workspace.OpenFeatureClass ("modle.dwg:polyline");
IFeatureLayer Fly = new FeatureLayerClass ();
Fly.FeatureClass = Fcls;
MapCtr.Map.AddLayer (Fly);
MapCtr.ActiveView.Refresh ();
}
B、整幅CAD圖的加載
當我們要加載整幅CAD圖時,需要使用下邊的代碼,這跟加載地物類有一定的區別,詳細地介紹請看代碼中的注析:
public void AddWholeCAD()
{
/*下邊的兩行代碼是定義一個CAD工作空間,然后打開它,但這次不是賦值給
IFeatureWorkspace對象,而是賦值給IWorkspace定義的對象*/
IWorkspaceFactory Fact = new CadWorkspaceFactoryClass();
IWorkspace Workspace = Fact.OpenFromFile(@"I:\test\",0);
//定義一個CAD畫圖空間,並把上邊打開的工作空間賦給它
ICadDrawingWorkspace dw = Workspace as ICadDrawingWorkspace;
//定義一個CAD的畫圖數據集,並且打開上邊指定的工作空間中一幅CAD圖
//然后賦值給CAD數據集
ICadDrawingDataset ds = dw.OpenCadDrawingDataset ("modle.DWG");
//通過ICadLayer類,把上邊得到的CAD數據局賦值給ICadLayer類對象的
//CadDrawingDataset屬性
ICadLayer CadLayer = new CadLayerClass();
CadLayer.CadDrawingDataset = ds;
//利用MapControl加載CAD層
MapCtr.Map.AddLayer (CadLayer);
MapCtr.ActiveView.Refresh ();
}
通過上邊的代碼和相關的解析,大家可能對整幅CAD圖的加載有一個了解,但要具體搞清楚它的含義,也不那么容易。這留給大家去慢慢體會,在這我談 談我自己的體會,但不一定正確。要打開數據集,首先要打開它的工作空間,至於什么是工作空間,我也說不太明白,但我的理解是,如果數據是保存在文件中的, 工作空間大概就是它對應的文件夾,如果是數據庫中的數據,我想大概就是對應的數據庫。打開數據空間后,在這因為是整幅CAD圖加載,所以跟以前的有點不 同,這也就是相當整個CAD圖就是一個數據集,所以要轉到CAD畫圖的工作空間,然后把CAD圖作為CAD數據集打開。為了在MapControl中加載 CAD層,必須使用ICadLayer控件的對象,因為MapCtr.Map.AddLayer ()方法中只能是ICadLayer的對象。
