本节摘要:组件式开发把 MapGIS 的能力做成一颗颗"零件",用 C# 把零件拼成自己的桌面程序。本节以对象模型为纲——服务器、数据库、要素类、要素四级向下钻取,写一个完整的"图斑统计器":连库、开类、遍历、统计、写回。读懂这四级对象,组件开发就入门了。
组件开发的地图只有一张,对象模型的层级:服务器是入口,代表一个运行的数据服务;数据库是仓库,地理数据库挂在其下;要素类是表格,同构要素的集合;要素是行,一个图斑、一条路。所有组件代码都在这四级台阶上爬上爬下。
# 对象模型四级与口诀 Server 服务器 入口 连上一个就有了一切 └ DataBase 数据库 仓库 空间与属性都在这里 └ FeatureClass 要素类 表 一类要素的同构集合 └ Feature 要素 行 一个图斑 一根线 # 口诀:连服务 开数据库 找要素类 遍历要素 # 每一级都有打开与关闭 配对使用是纪律 不是风格
四级模型的价值在于"一处学会处处会通"。第 2 章建库、第 3 章分析用的数据,与本节代码里操作的是同一套对象,只是入口不同——桌面菜单是给人点的,组件接口是给代码调的。掌握了对象模型,等于拿到了平台的"编程遥控器"。
阅读完本节,你应当能够:
需求来自耕地保护项目:全县耕地图斑三万八千个,按权属单位汇总面积,并把每个图斑的"是否超阈值"标志写回库里。工具给内业人员用,桌面程序形态——正对组件式的胃口。
第一步,连库开类。 连接部分的代码要防一手"服务没起"的经典事故:
using MapGIS.GeoDataBase; // 数据库对象命名空间 // 连接本地数据服务并打开地理数据库 var server = new Server(); if (!server.Connect("本地服务", "", "")) { MessageBox.Show("数据服务未启动 请先启动服务再运行本工具"); return; // 连不上就退出 别硬走 } var gdb = server.OpenGDB("耕地保护库"); // 打开地理数据库 var fc = gdb.GetXClass(XClsType.Fc, "耕地图斑") as SFeatureCls; if (fc == null) { MessageBox.Show("要素类不存在 检查名称拼写"); return; } // 输出:fc.Ready 为真 表示要素类可用 要素数 fc.Num
第二步,游标遍历与统计。 三万八要素不能一次全读进内存,游标是按批取数的正确姿势:
var stat = new Dictionary<string, double>(); // 权属单位 汇总面积 var cursor = fc.Select(new QueryDef()); // 空条件 全表游标 var f = new Feature(); int n = 0; while (cursor.Next(f) > 0) // 逐条推进 { string owner = f.Fields.GetStr("权属单位"); // 读属性 double area = f.Fields.GetDouble("椭球面积"); if (!stat.ContainsKey(owner)) stat[owner] = 0; stat[owner] += area; // 分组累加 n++; } cursor.Close(); // 游标用完即关 // 输出:n 为 38421 stat 含 217 个权属单位 // 经验:遍历大表时把进度条挂上 三万条也要跑几秒 无反馈会被当死机
第三步,结果写回与展示。 统计值既要导出报表,也要写回图斑做专题符号化的依据:
// 给要素类加一个短整型字段 存超阈值标志 if (fc.Fields.IndexOfField("超阈值") < 0) // 先查有没有 防重复加 { var fld = new FieldDefn("超阈值", FieldType.FldInt16); fc.Fields.Append(fld); } // 按权属均值阈值回写 第二遍游标只写超标的 double threshold = stat.Values.Average() * 1.5; // 阈值取均值一点五倍 var cursor2 = fc.Select(new QueryDef()); var f2 = new Feature(); while (cursor2.Next(f2) > 0) { string owner = f2.Fields.GetStr("权属单位"); bool over = f2.Fields.GetDouble("椭球面积") > threshold; f2.Values.SetItem("超阈值", over ? 1 : 0); // 改字段 cursor2.Update(f2); // 提交回写 } cursor2.Close(); fc.Dispose(); gdb.Dispose(); server.DisConnect(); // 逐级关闭 // 输出:约 6800 个图斑被标记为 1 后续符号化按此字段分级设色
三段代码合起来约五十行,一个能交付内业的工具成型了。复盘它的结构:连接防护、游标遍历、条件回写、逐级关闭——这四件事就是组件开发的基本功,换一个需求(管道检查、林地汇总),骨架原封不动,改的只是字段与逻辑。
⚠️ 常见坑:游标与连接不关。工具跑完图也出来了,但任务管理器里进程的句柄数一路涨,跑几轮后数据库连接池耗尽,全线报错。组件开发的铁律是"谁打开谁关闭",游标、要素类、数据库、服务器四级都要显式释放,用 try 与 finally 包住释放代码更稳。
图斑统计器是单窗口小工具,真实的组件式项目会长成多窗口、带权限、连服务端的桌面系统。工程化的三个升级方向:界面层用成熟的界面框架组织多窗体与停靠面板,地图控件只是其中一员;数据层把对象模型的访问封装成独立模块,界面不直接碰数据库对象;发布用安装项目把程序连同运行时打包,目标机器免装开发环境。
组件式与 6.3 的服务端开发不是竞争关系。桌面程序做重交互的内业台,服务端做对外共享——一个县域项目两条路线并行,各自吃各自擅长的场景,这在第 7 章的行业案例里会反复见到。
💡 关键直觉:组件式开发的性价比临界点在"交互复杂度"。界面上的拖拽勾选越多、专业编辑动作越多,组件式越值;如果只是查查看,网页就够了,别让 EXE 变成只用来显示地图的昂贵壳子。