《ArcGIS Engine+C#实例开发教程》第八讲 属性数据表的查询显示

简介: 原文:《ArcGIS Engine+C#实例开发教程》第八讲 属性数据表的查询显示 第一讲 桌面GIS应用程序框架的建立 第二讲 菜单的添加及其实现 第三讲 MapControl与PageLayoutControl同步 第四讲 状态栏信息的添加与实现 第五讲 鹰眼的实现 第六讲 右键菜单添加与实现 教程Bug及优化方案1 第七讲 图层符号选择器的实现1 第七讲 图层符号选择器的实现2 第八讲 属性数据表的查询显示 摘要:这一讲中,我们将实现图层属性数据表的查询显示。
原文: 《ArcGIS Engine+C#实例开发教程》第八讲 属性数据表的查询显示

在上一讲中,我们完成了图层符号选择器的制作。这一讲中,我们将实现图层属性数据表的查询显示。

在ArcMap中,单击图层右键菜单中的“Open Attribute Table”命令,便可弹出属性数据表。本讲将完成类似的功能,效果如下:

图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。实现函数如下:

 

/// <summary>

/// 根据图层字段创建一个只含字段的空DataTable

/// </summary>

/// <param name="pLayer"></param>

/// <param name="tableName"></param>

/// <returns></returns>

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 < 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的数据类型不同,故要进行转换。转换函数如下:

/// <summary>

/// 将GeoDatabase字段类型转换成.Net相应的数据类型

/// </summary>

/// <param name="fieldType">字段类型</param>

/// <returns></returns>

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:

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";

}

}

摘要:这一讲中,我们将实现图层属性数据表的查询显示。在ArcMap中,单击图层右键菜单中的“Open Attribute Table”命令,便可弹出属性数据表。本讲将完成类似的功能.

3.装载DataTable数据

从上一步得到的DataTable还没有数据,只有字段信息。因此,我们要通过ICursor从ITable中逐一取出每一行数据,即IRow。再创建DataTable中相应的DataRow,根据IRow设置DataRow信息,再将所有的DataRow添加到DataTable中,就完成了DataTable数据的装载。

为保证效率,一次最多只装载2000条数据到DataGridView。函数代码如下:

 

 /// <summary>

/// 填充DataTable中的数据

/// </summary>

/// <param name="pLayer"></param>

/// <param name="tableName"></param>

/// <returns></returns>

public static DataTable CreateDataTable(ILayer pLayer, string tableName)

{

//创建空DataTable

DataTable pDataTable = CreateDataTableByLayer(pLayer, tableName);

//取得图层类型

string shapeType = getShapeType(pLayer);

//创建DataTable的行对象

DataRow pDataRow = null;

//从ILayer查询到ITable

ITable pTable = pLayer as 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 < 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;

}

else

{

pRow = pCursor.NextRow();

}

}

return pDataTable;

}

上面的代码中涉及到一个获取图层类型的函数getShapeTape,此函数是通过ILayer判断图层类型的,代码如下:

/// <summary>

/// 获得图层的Shape类型

/// </summary>

/// <param name="pLayer">图层</param>

/// <returns></returns>

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";

default:

return "";

}

}

4.绑定DataTable到DataGridView

通过以上步骤,我们已经得到了一个含有图层属性数据的DataTable。现定义一个AttributeTableFrm类的成员变量:

 

 public DataTable attributeTable;

通过以下函数,我们很容易将其绑定到DataGridView控件中。

 

 /// <summary>

/// 绑定DataTable到DataGridView

/// </summary>

/// <param name="player"></param>

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的表名不允许含有“.”,因此我们用“_”替换。函数如下:

/// <summary>

/// 替换数据表名中的点

/// </summary>

/// <param name="FCname"></param>

/// <returns></returns>

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.Carto;

using ESRI.ArcGIS.Display;

using ESRI.ArcGIS.esriSystem;

添加成员变量:

 

 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函数中添加如下代码,以创建并打开属性表窗体。

 

 /// <summary>

/// Occurs when this command is clicked

/// </summary>

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环境下编译通过。

目录
相关文章
|
3月前
|
存储 安全 编译器
C# 11.0中的泛型属性:类型安全的新篇章
【1月更文挑战第23天】C# 11.0引入了泛型属性的概念,这一新特性为开发者提供了更高级别的类型安全性和灵活性。本文将详细探讨C# 11.0中泛型属性的工作原理、使用场景以及它们对现有编程模式的改进。通过深入了解泛型属性,开发者将能够编写更加健壮、可维护的代码,并充分利用C#语言的最新发展。
|
1月前
|
Java C#
C#学习相关系列之多线程(七)---Task的相关属性用法
C#学习相关系列之多线程(七)---Task的相关属性用法
|
3月前
|
开发框架 .NET C#
C# 10.0中的扩展属性与模式匹配:深入解析
【1月更文挑战第20天】C# 10.0引入了众多新特性,其中扩展属性与模式匹配的结合为开发者提供了更强大、更灵活的类型检查和代码分支能力。通过这一特性,开发者可以在不修改原始类的情况下,为其添加新的行为,并在模式匹配中利用这些扩展属性进行更精细的控制。本文将详细探讨C# 10.0中扩展属性与模式匹配的工作原理、使用场景以及最佳实践,帮助读者更好地理解和应用这一新功能。
|
3月前
|
运维 编译器 C#
C# 9.0中的本地函数属性:深化函数级别的控制
【1月更文挑战第17天】C# 9.0引入了本地函数属性的概念,允许开发者在本地函数上应用属性,从而进一步细化对函数行为的控制。这一新特性不仅增强了代码的可读性和可维护性,还为函数级别的编程提供了更多的灵活性。本文将探讨C# 9.0中本地函数属性的用法、优势以及可能的应用场景,帮助读者更好地理解并应用这一新功能。
|
3月前
|
SQL 开发框架 .NET
C#进阶-LINQ表达式之GroupBy分组查询
本篇文章我们将演示LINQ扩展包基础语法里的GroupBy分组查询,并实现投影等实际操作中常用的类型转换手法。目前LINQ支持两种语法,我会在每个案例前先用大家熟知的SQL语句表达,再在后面用C#的两种LINQ语法分别实现。LINQ语法第一次接触难免感到陌生,最好的学习方式就是在项目中多去使用,相信会有很多感悟。
58 0
|
4月前
|
XML 存储 JSON
C# | 使用Json序列化对象时忽略只读的属性
将对象序列化成为Json字符串是一个使用频率非常高的功能。Json格式具有很高的可读性,同时相较于XML更节省空间。 在开发过程中经常会遇到需要保存配置的场景,比如将配置信息保存在配置类型的实例中,再将这个对象序列化成为Json字符串并保存。当需要加载配置时,则是读取Json格式的字符串再将其还原成配置对象。在序列化的过程中,默认会将所有公开的属性和字段都序列化进入Json字符串中,这其中也会包含只读的属性或字段,而只读的属性和字段在反序列化的过程中其实是无意义的,也就是说这一部分存储是多余的。 本文将讲解如何在执行Json序列化时,忽略掉那些只读的属性和字段。
52 0
C# | 使用Json序列化对象时忽略只读的属性
|
4月前
|
C# 索引
C# | 【完全开源】手机号码归属地查询,一秒内百万次查询
这个开源项目是一个.NET库,可以通过手机号码获取号码归属地信息,包括运营商、国家、省份、城市、邮政编码、区号等信息。 该库加载了一个包含46万条数据的“中国手机号归属地信息”数据集,并实现了高速查询。在我的7年老笔记本上执行一百万次查询耗时不足一秒。
141 0
|
5月前
|
前端开发 C# 开发工具
Unity快手上手【熟悉unity编辑器,C#脚本控制组件一些属性之类的】
Unity快手上手【熟悉unity编辑器,C#脚本控制组件一些属性之类的】
103 0
|
8月前
|
存储 编译器 C#
《More effective C#》第二章 尽量采用隐式属性来表示可变的数据
《More effective C#》第二章 尽量采用隐式属性来表示可变的数据
|
9月前
|
C#
C#属性的get与set
C#属性的get与set