实现的功能:
1.与AxMapControl选择联动 获取AxMapControl选中项记录展示 双击表头缩放
2.属性编辑 可控制允许编辑字段
3.加载效率优化 实现打开时加载固定数量的记录 滑动到底部再次加载固定数量的记录
4.列菜单 字段计算器和计算几何
5.上部菜单 取消选择 反选 按属性选择 删除记录
6.下部菜单 切换显示所有记录和所选记录
构成:属性表使用两个GridControl构成,通过切换可视状态展示记录,上部和下部菜单使用自定义控件,所有控件都放在DockPanel中使其可以拖动。
【显示选择记录】GridView在之后称为选择表
【显示所有记录】GridView在之后称为所有表
1.选择联动的实现
(1)通过AxMapControl选择属性表:
因为的选择表中的记录,在每次只加载固定数量记录得所有表中不一定存在,所有先将AxMapControl中的选择记录更新到选择表中,再在所有表中选中行。绑定AxMapControl左键弹起事件
通过遍历ArcMapControl的要素图层的选择集接口 获取选中的要素 然后加入选择表中
主要方法
获取所有要素图层
/// <summary>
/// 获取AxMap内所有要素图层
/// </summary>
/// <param name="AXC"></param>
/// <returns>要素图层列表</returns>
public static List<IFeatureLayer> GetFeatureLayers(AxMapControl AXC)
{
UID uid = new UIDClass();
uid.Value = "{40A9E885-5533-11d0-98BE-00805F7CED21}";//FeatureLayer
IEnumLayer a = AXC.Map.Layers[uid];
List<IFeatureLayer> layers = new List<IFeatureLayer>();
ILayer IL = null;
while ((IL = a.Next()) != null)
{
layers.Add(IL as IFeatureLayer);
}
return layers;
}
获取选中的要素 然后加入选择表中
public static void GetSelectionDataTable(IFeatureSelection IFS, string tableName, int startOid = 0, DataTable dt = null, int loadLength = 2000)
{
///参数解释
IFeatureSelection IFS :要素图层的选择集 通过 IFeatureLayer as IFeatureLayer获得
string tableName :表名称
int startOid :控制开始的Oid 因为每次只加载2000条记录 在下滑到底部后 之前载入的记录不需要再重新载入 通过此参数控制开始载入的OID值
DataTable dt :选择表GridControl的数据源DataTable 如果传入此参数 获取到得记录会加入此DataTable中 而不是新生成 DataTable
LoadLength : 需要载入的记录数 (如果为负数 则会载入所有记录)
///
IQueryFilter pQueryFilter;
DataTable pDataTable;
if (startOid != 0)
{
pDataTable = dt;
pQueryFilter = new QueryFilterClass();
pQueryFilter.WhereClause = string.Format("\"{0}\" > {1} ", (IFS as IFeatureLayer).FeatureClass.OIDFieldName, startOid); //筛选OID大于startOid的记录
}
else
{
//startOid为0表示重新生成DataTable 下面的函数是通过图层的字段生成DataTable的列名和格式
pDataTable = CreateDataTableByLayer(IFS as ILayer, tableName);
pQueryFilter = null;
}
ISelectionSet ISS = IFS.SelectionSet;
ICursor cursor;
ISS.Search(pQueryFilter, false, out cursor); //获取游标
// IEnumIDs IID = ISS.IDs;
//取得图层类型
string shapeType = getShapeType(IFS as ILayer); //用来填充Shape字段
//创建DataTable的行对象
DataRow pDataRow = null;
//从ILayer查询到ITable
IFeatureLayer IFL = IFS as IFeatureLayer;
ITable featureTable = IFL.FeatureClass as ITable;
DataTable AllData = DataProductionPlatform.mainMap.LayerAttributeDict[IFL].GridControlForAll.DataSource as DataTable;
int id;
int n = 0;
IRow irow = cursor.NextRow();
if (irow == null)
{ //没有选中记录 赋值选择表的数据源为刚获取的空 DataTable 相当于清空记录
DataProductionPlatform.mainMap.LayerAttributeDict[IFL].gridControlForSelect.DataSource = pDataTable;
return;
}
while ((id = irow.OID) >= 0)
{
DataRow dr = AllData.Rows.Find(id); //之前将DataTable的索引设置为OID列 因为通过索引搜索更快
if (dr != null)//如果总表中存在此id 读取总表的行 应该效率更快
{
pDataTable.ImportRow(dr);
}
else //如果总表中不存在此id 读取要素类
{
//新建DataTable的行对象
pDataRow = pDataTable.NewRow();
for (int i = 0; i < irow.Fields.FieldCount; i++)
{
switch (irow.Fields.get_Field(i).Type)
{
case esriFieldType.esriFieldTypeGeometry://如果字段类型为esriFieldTypeGeometry,则根据图层类型设置字段值
pDataRow[i] = shapeType;
break;
//当图层类型为Anotation时,要素类中会有esriFieldTypeBlob类型的数据,
//其存储的是标注内容,如此情况需将对应的字段值设置为Element
case esriFieldType.esriFieldTypeBlob:
pDataRow[i] = "Element";
break;
default:
pDataRow[i] = irow.Value[i];
break;
}
}
//添加DataRow到DataTable
pDataTable.Rows.Add(pDataRow);
}
n++;
//为保证效率,一次只装载最多条记录
if (n == loadLength)
{
break;
}
irow = cursor.NextRow();
if (irow == null) break;
}
System.Runtime.InteropServices.Marshal.ReleaseComObject(cursor);
if (dt == null) DataProductionPlatform.mainMap.LayerAttributeDict[IFL].gridControlForSelect.DataSource = pDataTable; //更新选择表的数据源
}
在选择表更新完成后使用封装好的方法更新所有表的选中行
/// <summary>
///更新GridViewAll的选中项
/// </summary>
/// <param name="ifeatureLayer"></param>
public static void UpdateSelectRow(this IFeatureLayer ifeatureLayer,int StartNum=0)
{
ISelectionSet ISS = (ifeatureLayer as IFeatureSelection).SelectionSet;
IEnumIDs IID = ISS.IDs;
DevExpress.XtraGrid.Views.Grid.GridView GVAll = DataProductionPlatform.mainMap.LayerAttributeDict[ifeatureLayer].gridControlForAll.MainView as DevExpress.XtraGrid.Views.Grid.GridView;
int oid;
while ((oid = IID.Next()) < StartNum && oid !=-1) //StartNum之前的行不进行处理
{
}
if(StartNum==0) GVAll.ClearSelection(); //StartNum为0时表示选择集更新 清除All表所有选中项重新选择 StartNum不为0时 表示All表触发了下滑增加记录事件 不清除选择只选择增加的记录
GVAll.BeginUpdate();//暂停刷新 提升效率
do
{
System.Data.DataTable DT = (GVAll.GridControl.DataSource as System.Data.DataTable); ///所有表的数据源
System.Data.DataRow DTrow = DT.Rows.Find(oid);
if (DTrow != null)
{
int findRow = DT.Rows.IndexOf(DTrow);
GVAll.SelectRow(findRow);
}
else { break; } //因为OID按大小排序 如果没找到表示所有表中还未载入到此OID 之后的OID也没有载入 直接跳出循环
} while ((oid = IID.Next()) >= 0);
GVAll.EndUpdate();
}
(2)通过属性表选择AxMapControl:
通过GridView的鼠标弹起事件,首先通过GridView 的Tag属性获取对应的要素图层(打开属性表时就将对应的IFeatureLayer对象放入到GridView的Tag中方便调用),在获取对应的选择集接口,将选中行对应的要素通过ISelectionSet.add添加进选择集
private void UpdateMapSelect(object sender, MouseEventArgs e)
{
GridView GV = (GridView)sender;
if( e.Button==MouseButtons.Left)
{
System.Collections.Generic.IList<int> mList = new System.Collections.Generic.List<int>();
mList = GV.GetSelectedRows(); //获取所有选中行的Handle
IFeatureSelection ifs = GV.Tag as IFeatureSelection;
ifs.SelectionSet = null; //清空要素图层的选择集
ISelectionSet ISS = ifs.SelectionSet; ///获取选择集
foreach (int oid in mList)
{
ISS.Add(int.Parse(GV.GetDataRow(oid)[this.oidString].ToString()));//通过Handle获取对应的行的OID值 this.oidString为之前获取的OID字段名
}
ifs.SelectionSet = ISS; ///将添加后的选择集赋值到要素图层
mainMap.LayerAttributeDict[GV.Tag as IFeatureLayer].LoMenu.Updatelabel();
///更新下部菜单的选中数量
axMapC.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeoSelection, GV.Tag as IFeatureLayer, axMapC.ActiveView.Extent);
//刷新显示 仅刷新选择和当前处理的图层 减少卡顿
(m_pLayer as IFeatureLayer).UpdateSelectGV(false);
//主要是调用上面的 GetSelectionDataTable方法更新选择集
}
}
其他:
1.对 GridView 进行大量更新时,应使用 BeginUpdate() BeginDataUpdate() 停止GridView的刷新 提升数据载入效率。
2.DataTable 应将保存OID的的列设置为主键,需要访问时使用DataTable.Rows.Find(id)方法 ,使用主键获取数据,提升效率。
3.需要对AxMapControl进行刷新操作时应仅刷新修改的部分避免卡顿,axMapC.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeoSelection, GV.Tag as IFeatureLayer, axMapC.ActiveView.Extent),在保证需求的情况下尽量缩小刷新的部分。
4.仅需要访问OID时使用IEnumIDs接口,获取速度最快