天天看點

《ArcGIS Engine+C#執行個體開發教程》第八講 屬性資料表的查詢顯示

<a href="http://www.cnblogs.com/SunYu/archive/2010/11/26/1888545.html">第一講 桌面GIS應用程式架構的建立</a>

<a href="http://www.cnblogs.com/SunYu/archive/2010/11/26/1888548.html">第二講 菜單的添加及其實作</a>

<a href="http://www.cnblogs.com/SunYu/archive/2010/11/26/1888551.html">第三講 MapControl與PageLayoutControl同步</a>

<a href="http://www.cnblogs.com/SunYu/archive/2010/11/26/1888553.html">第四講 狀态欄資訊的添加與實作</a>

<a href="http://www.cnblogs.com/SunYu/archive/2010/11/26/1888555.html">第五講 鷹眼的實作</a>

<a href="http://www.cnblogs.com/SunYu/archive/2010/11/26/1888557.html">第六講 右鍵菜單添加與實作</a>

<a href="http://www.cnblogs.com/SunYu/archive/2010/11/26/1888559.html">教程Bug及優化方案1</a>

<a href="http://www.cnblogs.com/SunYu/archive/2010/11/26/1888565.html">第七講 圖層符号選擇器的實作1</a>

<a href="http://www.cnblogs.com/SunYu/archive/2010/11/26/1888567.html">第七講 圖層符号選擇器的實作2</a>

<a href="http://www.cnblogs.com/SunYu/archive/2010/11/26/1888573.html">第八講 屬性資料表的查詢顯示</a>

摘要:這一講中,我們将實作圖層屬性資料表的查詢顯示。在ArcMap中,單擊圖層右鍵菜單中的“Open Attribute Table”指令,便可彈出屬性資料表。本講将完成類似的功能.

在上一講中,我們完成了圖層符号選擇器的制作。這一講中,我們将實作圖層屬性資料表的查詢顯示。

在ArcMap中,單擊圖層右鍵菜單中的“Open Attribute Table”指令,便可彈出屬性資料表。本講将完成類似的功能,效果如下:

《ArcGIS Engine+C#執行個體開發教程》第八講 屬性資料表的查詢顯示

圖1

資料表顯示,我們用了DataGridView控件。DataGridView控件提供一種強大而靈活的以表格形式顯示資料的方式。可以使用 DataGridView控件來顯示少量資料的隻讀視圖,也可以對其進行縮放以顯示特大資料集的可編輯視圖。我們可以很友善地把一個DataTable作為資料源綁定到DataGridView控件中。

本講的思路大體如下:首先根據圖層屬性中的字段建立一個空的DataTable,然後根據資料内容一行行填充DataTable資料,再将DataTable綁定到DataGridView控件,最後調用并顯示屬性表窗體。

1.建立屬性表窗體

建立一個Windows窗體,命名為“AttributeTableFrm.cs”。

從工具箱拖一個DataGridView控件到窗體,并将其Dock屬性設定為“Fill”。

添加如下引用:

using ESRI.ArcGIS.Carto;

using ESRI.ArcGIS.Controls;

using ESRI.ArcGIS.esriSystem;

using ESRI.ArcGIS.SystemUI;

using ESRI.ArcGIS.Geometry;

using ESRI.ArcGIS.Geodatabase;

2.建立空DataTable

首先傳入ILayer,再查詢到ITable,從ITable中的Fileds中獲得每個Field,再根據Filed設定DataTable的DataColumn,由此建立一個隻含圖層字段的空DataTable。實作函數如下:

/// &lt;summary&gt;

/// 根據圖層字段建立一個隻含字段的空DataTable

/// &lt;/summary&gt;

/// &lt;param name="pLayer"&gt;&lt;/param&gt;

/// &lt;param name="tableName"&gt;&lt;/param&gt;

/// &lt;returns&gt;&lt;/returns&gt;

private static DataTable CreateDataTableByLayer(ILayer pLayer, string tableName)

{

//建立一個DataTable表

DataTable pDataTable = new DataTable(tableName);

//取得ITable接口

ITable pTable = pLayer as ITable;

IField pField = null;

DataColumn pDataColumn;

//根據每個字段的屬性建立DataColumn對象

for (int i = 0; i &lt; pTable.Fields.FieldCount; i++)

pField = pTable.Fields.get_Field(i);

//建立一個DataColumn并設定其屬性

pDataColumn = new DataColumn(pField.Name);

if (pField.Name == pTable.OIDFieldName)

pDataColumn.Unique = true;//字段值是否唯一

}

//字段值是否允許為空

pDataColumn.AllowDBNull = pField.IsNullable;

//字段别名

pDataColumn.Caption = pField.AliasName;

//字段資料類型

pDataColumn.DataType = System.Type.GetType(ParseFieldType(pField.Type));

//字段預設值

pDataColumn.DefaultValue = pField.DefaultValue;

//當字段為String類型是設定字段長度

if (pField.VarType == 8)

pDataColumn.MaxLength = pField.Length;

//字段添加到表中

pDataTable.Columns.Add(pDataColumn);

pField = null;

pDataColumn = null;

return pDataTable;

因為GeoDatabase的資料類型與.NET的資料類型不同,故要進行轉換。轉換函數如下:

/// 将GeoDatabase字段類型轉換成.Net相應的資料類型

/// &lt;param name="fieldType"&gt;字段類型&lt;/param&gt;

public static string ParseFieldType(esriFieldType fieldType)

switch (fieldType)

case esriFieldType.esriFieldTypeBlob:

return "System.String";

case esriFieldType.esriFieldTypeDate:

return "System.DateTime";

case esriFieldType.esriFieldTypeDouble:

return "System.Double";

case esriFieldType.esriFieldTypeGeometry:

case esriFieldType.esriFieldTypeGlobalID:

case esriFieldType.esriFieldTypeGUID:

case esriFieldType.esriFieldTypeInteger:

return "System.Int32";

case esriFieldType.esriFieldTypeOID:

case esriFieldType.esriFieldTypeRaster:

case esriFieldType.esriFieldTypeSingle:

return "System.Single";

case esriFieldType.esriFieldTypeSmallInteger:

case esriFieldType.esriFieldTypeString:

default:

3.裝載DataTable資料

從上一步得到的DataTable還沒有資料,隻有字段資訊。是以,我們要通過ICursor從ITable中逐一取出每一行資料,即IRow。再建立DataTable中相應的DataRow,根據IRow設定DataRow資訊,再将所有的DataRow添加到DataTable中,就完成了DataTable資料的裝載。

為保證效率,一次最多隻裝載2000條資料到DataGridView。函數代碼如下:

 /// &lt;summary&gt;

/// 填充DataTable中的資料

public static DataTable CreateDataTable(ILayer pLayer, string tableName)

//建立空DataTable

DataTable pDataTable = CreateDataTableByLayer(pLayer, tableName);

//取得圖層類型

string shapeType = getShapeType(pLayer);

//建立DataTable的行對象

DataRow pDataRow = null;

//從ILayer查詢到ITable

ICursor pCursor = pTable.Search(null, false);

//取得ITable中的行資訊

IRow pRow = pCursor.NextRow();

int n = 0;

while (pRow != null)

//建立DataTable的行對象

pDataRow = pDataTable.NewRow();

for (int i = 0; i &lt; pRow.Fields.FieldCount; i++)

//如果字段類型為esriFieldTypeGeometry,則根據圖層類型設定字段值

if (pRow.Fields.get_Field(i).Type == esriFieldType.esriFieldTypeGeometry)

pDataRow[i] = shapeType;

//當圖層類型為Anotation時,要素類中會有esriFieldTypeBlob類型的資料,

//其存儲的是标注内容,如此情況需将對應的字段值設定為Element

else if (pRow.Fields.get_Field(i).Type == esriFieldType.esriFieldTypeBlob)

pDataRow[i] = "Element";

else

pDataRow[i] = pRow.get_Value(i);

//添加DataRow到DataTable

pDataTable.Rows.Add(pDataRow);

pDataRow = null;

n++;

//為保證效率,一次隻裝載最多條記錄

if (n == 2000)

pRow = null;

pRow = pCursor.NextRow();

上面的代碼中涉及到一個擷取圖層類型的函數getShapeTape,此函數是通過ILayer判斷圖層類型的,代碼如下:

/// 獲得圖層的Shape類型

/// &lt;param name="pLayer"&gt;圖層&lt;/param&gt;

public static string getShapeType(ILayer pLayer)

IFeatureLayer pFeatLyr = (IFeatureLayer)pLayer;

switch (pFeatLyr.FeatureClass.ShapeType)

case esriGeometryType.esriGeometryPoint:

return "Point";

case esriGeometryType.esriGeometryPolyline:

return "Polyline";

case esriGeometryType.esriGeometryPolygon:

return "Polygon";

return "";

4.綁定DataTable到DataGridView

通過以上步驟,我們已經得到了一個含有圖層屬性資料的DataTable。現定義一個AttributeTableFrm類的成員變量:

 public DataTable attributeTable;

通過以下函數,我們很容易将其綁定到DataGridView控件中。

/// 綁定DataTable到DataGridView

/// &lt;param name="player"&gt;&lt;/param&gt;

public void CreateAttributeTable(ILayer player)

string tableName;

tableName = getValidFeatureClassName(player .Name );

attributeTable = CreateDataTable(player,tableName );

this.dataGridView1 .DataSource = attributeTable ;

this.Text = "屬性表[" + tableName + "] " + "記錄數:"+attributeTable.Rows.Count .ToString();

因為DataTable的表名不允許含有“.”,是以我們用“_”替換。函數如下:

/// 替換資料表名中的點

/// &lt;param name="FCname"&gt;&lt;/param&gt;

public static string getValidFeatureClassName(string FCname)

int dot = FCname.IndexOf(".");

if (dot != -1)

return FCname.Replace(".", "_");

return FCname;

5.調用屬性表窗體

通過1-4步驟,我們封裝了一個AttributeTableFrm類,此類能夠由ILayer顯示圖層中的屬性表資料。那怎麼調用AttributeTableFrm呢?

前面已經提到,我們是在TOCControl選中圖層的右鍵菜單中彈出屬性表窗體的,是以我們需要添加一個菜單項到TOCControl中Layer的右鍵菜單。而在第六講中,我們采用的是AE中的IToolbarMenu實作右鍵菜單的,故我們還需自定義一個Command,實作打開屬性表的功能。

以ArcGIS的Base Command為模闆建立項“OpenAttributeTable.cs”。

注意:建立Base Command模闆時,會彈出一個對話框讓我們選擇模闆适用對象,這時我們要選擇MapControl、PageLayoutControl,即選擇第二項或者倒數第二項。

using ESRI.ArcGIS.Display;

添加成員變量:

 private ILayer m_pLayer;

修改構造函數為:

 public OpenAttributeTable(ILayer pLayer)

//

// TODO: Define values for the public properties

base.m_category = ""; //localizable text

base.m_caption = "打開屬性表"; //localizable text

base.m_message = "打開屬性表"; //localizable text

base.m_toolTip = "打開屬性表"; //localizable text

base.m_name = "打開屬性表"; //unique id, non-localizable (e.g. "MyCategory_MyCommand")

m_pLayer = pLayer;

try

// TODO: change bitmap name if necessary

string bitmapResourceName = GetType().Name + ".bmp";

base.m_bitmap = new Bitmap(GetType(), bitmapResourceName);

catch (Exception ex)

System.Diagnostics.Trace.WriteLine(ex.Message, "Invalid Bitmap");

再在On_Click函數中添加如下代碼,以建立并打開屬性表窗體。

/// Occurs when this command is clicked

public override void OnClick()

// TODO: Add OpenAttributeTable.OnClick implementation

AttributeTableFrm attributeTable = new AttributeTableFrm();

attributeTable.CreateAttributeTable(m_pLayer);

attributeTable.ShowDialog();

至此,我們完成了OpenAttributeTable指令。顯然,我們要在TOCControl的OnMouseDown事件中調用此指令。

因為,目前選中的圖層參數,即ILayer是通過OpenAttributeTable的構造函數傳入的,而選中的ILayer是動态變化的,是以我們無法在窗體初始化的Form1_Load事件中就添加OpenAttributeTable菜單項到右鍵菜單。但我們可以在OnMouseDown事件中動态添加OpenAttributeTable菜單項。

要注意的是,最後我們必須移除添加的OpenAttributeTable菜單項,不然每次按下右鍵都會添加此菜單項,将造成右鍵菜單中含有多個OpenAttributeTable菜單項。

修改TOCControl的OnMouseDown事件的部分代碼如下:

 private void axTOCControl1_OnMouseDown(object sender, ITOCControlEvents_OnMouseDownEvent e)

//……

//彈出右鍵菜單

if (item == esriTOCControlItem.esriTOCControlItemMap)

m_menuMap.PopupMenu(e.x, e.y, m_tocControl.hWnd);

if (item == esriTOCControlItem.esriTOCControlItemLayer)

//動态添加OpenAttributeTable菜單項

m_menuLayer.AddItem(new OpenAttributeTable(layer), -1, 2, true, esriCommandStyles.esriCommandStyleTextOnly);

m_menuLayer.PopupMenu(e.x, e.y, m_tocControl.hWnd);

//移除OpenAttributeTable菜單項,以防止重複添加

m_menuLayer.Remove(2);

6.編譯運作

按下F5,編譯運作程式,相信你已經實作了開篇處展示的屬性表效果了吧!

以上代碼在Windows XP Sp3 + VS2005 + AE9.2環境下編譯通過。

繼續閱讀