首页 / 资讯中心 / 文章详情

ArcGIS+C#二次开发实战:地图编辑、空间分析与网络分析落地指南

ArcGIS+C#二次开发实战:地图编辑、空间分析与网络分析落地指南 ★ FEATURED ARTICLE
简介这份资源面向具备一定.NET基础的GIS开发者与测绘、地信专业学生提供ArcGIS与C#二次开发的完整工程源码用于解决地图编辑、空间分析与网络分析等定制化需求。压缩包共282个文件约911KB以99个cs源码文件为核心配合37个resx与resources资源文件、71个bmp位图及cur、ico等图标素材另有csproj、sln工程文件与少量exe、dll构成可直接编译运行的桌面GIS项目。内容围绕ArcEngine展开涵盖点线面要素的创建、修改与删除属性更新与版本管理缓冲区、叠置等空间分析调用以及网络数据集的路径选择与服务区划分并涉及ArcGIS Server发布地图服务的思路。已有431人学习适合作为课程设计、毕业设计或GIS工具开发的参考案例帮助读者理解接口调用方式与工程组织逻辑快速上手二次开发。1. ArcGISC#二次开发从地图编辑到网络分析的落地路线如果你手头有一份 ArcGIS 的桌面授权又恰好会写 C#那这套组合能做的事情远比拖拽工具箱多得多。地图编辑、空间分析、网络分析这三个词放在一起指向的是一类很具体的需求把 ArcGIS 从“点按钮的软件”变成“嵌进业务流程里的引擎”。比如批量给几千条管线做连通性检查、按自定义规则自动打断线要素、算完最优路径后直接写回业务库——这些用 ArcMap 手动点一天做不完用 C# 调 ArcObjects 或 ArcGIS Pro SDK几分钟跑完。这份笔记面向的是已经装好 ArcGIS、写过一点 C#、但还没把两者真正接起来的人。我会按“先搞清楚用哪套 API、再动手写编辑和分析、最后把网络分析和坑讲透”的顺序推。热词里那些 arcgis安装10.8、arcgis pro 3.7 登录问题、arcgis裁剪影像 之类的本质都是环境问题环境不通后面全白搭所以第 2 章先把选型和环境钉死。至于 c#高级编程、c#类库、c#线程 这些会在具体代码里自然带出来不单独讲语法。2. 选型与环境ArcObjects 还是 ArcGIS Pro SDK2.1 两套 API 的边界先想清楚再动手ArcGIS 的 C# 二次开发有两条主线选错了后面返工成本很高。第一条是ArcObjects绑定的是 ArcMap / ArcCatalog 那一代桌面产品10.x。它的能力最全地图编辑、空间分析、网络分析全都有缺点是 COM 组件、32 位、部署麻烦而且 Esri 已经不再对它做功能更新。第二条是ArcGIS Pro SDK for .NET绑定 ArcGIS Pro基于 .NET 6/864 位走的是现代插件框架但它的 Network Analyst 能力要通过 ArcPy 或地理处理工具间接调纯 SDK 直接操作网络数据集的接口没有 ArcObjects 那么细。我一般的判断标准是这样的需求特征推荐原因已有 ArcMap 10.x 授权要深度操作网络数据集ArcObjectsINetworkDataset 等接口直接可用新项目要长期维护界面要现代ArcGIS Pro SDK.NET 生态64 位部署干净只是批量跑分析、不需要交互界面ArcPy C# 进程调用最省事绕开 COM要嵌入已有 WinForm/WPF 业务系统ArcObjects 或 Pro SDK 按授权定看客户装的是哪个热词里频繁出现的 arcgis安装10.8、arcgis安装license无法启动基本都是 ArcObjects 路线的环境问题。10.8 是 ArcMap 最后一个大版本装完之后 License 起不来九成是 License Manager 服务没起或者防火墙拦了 27000 端口。这个后面避坑章细说。2.2 环境搭起来的最小步骤以 ArcObjects Visual Studio 为例走一遍能跑通的最小配置。第一步确认 ArcGIS Desktop 装好且能正常打开 ArcMap。打开不了就别往下走先解决授权。第二步在 Visual Studio 里新建一个 .NET Framework 4.8 的类库或 WinForm 项目。注意必须是 .NET Framework不能是 .NET Core/.NET 6ArcObjects 的 COM 互操作不支持后者。第三步添加引用。在“引用”里勾选 ESRI.ArcGIS 系列常用的几个是ESRI.ArcGIS.System ESRI.ArcGIS.Geodatabase ESRI.ArcGIS.Carto ESRI.ArcGIS.Geometry ESRI.ArcGIS.DataSourcesFile ESRI.ArcGIS.DataSourcesGDB ESRI.ArcGIS.NetworkAnalyst ESRI.ArcGIS.Controls // 做界面才需要第四步初始化许可。任何调用 ArcObjects 的程序第一件事是绑许可否则一调接口就抛异常。using ESRI.ArcGIS.esriSystem; using ESRI.ArcGIS; // 在程序入口Main 或窗体构造函数最前面执行 private static void InitLicense() { // 单机版用 esriLicenseProductCodeEngine 或 ArcInfo // 这里用 ArcInfo功能最全 IAoInitialize aoInit new AoInitializeClass(); esriLicenseStatus status aoInit.Initialize( esriLicenseProductCode.esriLicenseProductCodeArcInfo); if (status ! esriLicenseStatus.esriLicenseCheckedOut) { throw new Exception(ArcGIS 许可初始化失败状态 status); } // 程序退出时记得 aoInit.Shutdown() }这段代码的逻辑很直白AoInitialize是 ArcObjects 的许可门卫Initialize传入你要用的产品级别返回状态。只有返回esriLicenseCheckedOut才算拿到许可。参数上esriLicenseProductCodeArcInfo对应 ArcInfo 级别如果你只有 ArcEditor 或 ArcView换成对应枚举但注意 Network Analyst 扩展需要额外CheckOutExtension。// 网络分析扩展需要单独签出 status aoInit.CheckOutExtension(esriLicenseExtensionCode.esriLicenseExtensionCodeNetwork); if (status ! esriLicenseStatus.esriLicenseCheckedOut) { throw new Exception(Network Analyst 扩展签出失败); }CheckOutExtension是很多人漏掉的一步。产品级许可拿到了不代表扩展模块能用。现象就是代码编译没问题一调INetworkAnalyst相关接口就报没有许可。参数esriLicenseExtensionCodeNetwork对应 Network Analyst空间分析对应esriLicenseExtensionCodeSpatial3D 对应esriLicenseExtensionCode3DAnalyst。提示许可签出是有数量限制的调试时反复启动程序容易把许可占满记得在FormClosed或Main结束时调aoInit.Shutdown()释放。3. 地图编辑与空间分析的代码落地3.1 用 IFeatureCursor 做批量编辑别用 IFeatureCursor 逐条 Update地图编辑的核心对象是IFeatureClass和IFeature。新手最容易翻车的地方是逐条feature.Store()几千条数据能跑几分钟。正确做法是用游标批量操作。下面这段是给一个面要素类批量写入字段值的典型写法using ESRI.ArcGIS.Geodatabase; using ESRI.ArcGIS.Geometry; public void BatchUpdateField(IFeatureClass fc, string fieldName, object newValue) { // 用 IFeatureCursor 打开更新游标第二个参数 false 表示非回收模式 IFeatureCursor cursor fc.Update(null, false); IFeature feature cursor.NextFeature(); // 找到目标字段的索引循环外查一次别在循环里查 int idx fc.FindField(fieldName); if (idx 0) throw new Exception(字段不存在 fieldName); while (feature ! null) { feature.set_Value(idx, newValue); cursor.UpdateFeature(feature); // 关键用游标更新不是 feature.Store() feature cursor.NextFeature(); } // 释放 COM 对象否则文件锁不释放 System.Runtime.InteropServices.Marshal.ReleaseComObject(cursor); }逻辑说明fc.Update(null, false)打开一个更新游标null表示不过滤false表示不用 recycling回收模式会复用同一个对象批量读快但写有坑。FindField放在循环外是性能关键每次循环查字段索引是常见的性能杀手。cursor.UpdateFeature比feature.Store()快因为它走的是游标缓冲。参数说明Update的第一个参数是IQueryFilter传null表示全表第二个参数recycling在只读场景可以传true提速但写场景必须false。Marshal.ReleaseComObject是 ArcObjects 的血泪经验不释放游标shapefile 或 gdb 会被锁住下次打开就报“正在被其他程序使用”。3.2 空间分析用 IGeoProcessor 调工具还是纯接口空间分析有两条路。一条是IGeoProcessor调现成的 GP 工具比如 Buffer、Clip、Intersect另一条是直接用ITopologicalOperator等几何接口自己算。前者省事后者快且可控。调 GP 工具的写法using ESRI.ArcGIS.Geoprocessor; using ESRI.ArcGIS.AnalysisTools; public void RunBuffer(string inputPath, string outputPath, double distance) { Geoprocessor gp new Geoprocessor(); gp.OverwriteOutput true; // 允许覆盖同名输出 // Buffer 工具的参数按顺序塞 Buffer bufferTool new Buffer(inputPath, outputPath, distance.ToString()); IGeoProcessorResult result (IGeoProcessorResult)gp.Execute(bufferTool, null); if (result.Status ! esriJobStatus.esriJobSucceeded) { // 拿详细报错信息别只看状态 for (int i 0; i gp.MessageCount; i) Console.WriteLine(gp.GetMessage(i)); } }逻辑说明Geoprocessor是 GP 工具的托管包装Execute同步执行。OverwriteOutput true很关键否则输出已存在时直接失败。参数按工具定义的顺序传Buffer是输入、输出、距离。参数说明distance.ToString()这里没带单位如果输入数据是地理坐标系度距离单位就是度结果会离谱。正确做法是确保输入是投影坐标系或者距离字符串带单位如1000 Meters。这是空间分析最常见的翻车点之一热词里 arcgis做坡度图、arcgis裁剪影像 都涉及坐标系问题。如果只是做简单的几何运算比如判断相交、求并集直接用接口更快// 判断两个几何是否相交 ITopologicalOperator topoOp (ITopologicalOperator)geometry1; if (topoOp.IsSimple false) topoOp.Simplify(); // 先简化否则结果可能异常 bool intersects topoOp.Intersects(geometry2);Simplify()这一步很多人省掉结果Intersects返回的结果时对时错属于典型的玄学问题。原因是几何本身有自相交或未闭合拓扑操作前必须先简化。4. 网络分析从数据集构建到路径求解4.1 网络数据集必须先建好代码只是调用方网络分析的前提是有一个建好的 Network Dataset。这一步通常在 ArcCatalog 里手动建或者用 Python 脚本建。C# 代码能做的是加载它、设置分析参数、求解。加载网络数据集using ESRI.ArcGIS.NetworkAnalyst; using ESRI.ArcGIS.Geodatabase; public INetworkDataset LoadNetworkDataset(IWorkspace workspace, string datasetName) { // 找到网络数据集所在的 feature dataset IFeatureWorkspace fw (IFeatureWorkspace)workspace; IDatasetContainer3 dc (IDatasetContainer3)fw; // 遍历找目标网络数据集 for (int i 0; i dc.DatasetCount; i) { IDataset ds dc.get_Dataset(i); if (ds.Name datasetName ds is INetworkDataset) return (INetworkDataset)ds; } throw new Exception(未找到网络数据集 datasetName); }逻辑说明网络数据集在 gdb 里是特殊对象不能当普通 feature class 打开。IDatasetContainer3是容器接口遍历找到INetworkDataset。参数datasetName是网络数据集的名字不是路径。拿到INetworkDataset后要创建INAContext才能做分析// 创建分析上下文 INetworkDataset nds LoadNetworkDataset(workspace, RoadNetwork); INAContext naContext new NAContextClass(); naContext.Initialize(nds); // 设置求解器为路径分析 INASolver naSolver new NARouteSolverClass(); naContext.Solver naSolver;NAContext是网络分析的会话对象Initialize绑定数据集Solver决定做哪类分析。路径分析用NARouteSolverClass服务区分析用NAServiceAreaSolverClass最近设施用NAClosestFacilitySolverClass。4.2 路径求解的完整流程与参数路径分析要设停靠点、求解、读结果。停靠点用NAClass承载// 创建停靠点要素类 INAClass naClass naContext.CreateClass(Stops); naContext.Classes.Add(naClass); // 添加两个停靠点 IFeatureClass stopsFC naClass.FeatureClass; IFeature stop1 stopsFC.CreateFeature(); stop1.Shape point1; // point1 是 IPoint stop1.Store(); IFeature stop2 stopsFC.CreateFeature(); stop2.Shape point2; stop2.Store(); // 求解 naContext.Solver.Solve(naContext, null, null); // 读结果 INAClass routeClass naContext.Classes.get_ItemByName(Routes); IFeatureCursor cursor routeClass.FeatureClass.Search(null, false); IFeature route cursor.NextFeature(); // route.Shape 就是路径几何逻辑说明CreateClass创建分析用的临时要素类Stops是停靠点Routes是结果。停靠点必须Store()之后求解器才能读到。Solve的第二个参数是IGPMessages传null表示不收集消息调试时建议传一个对象进去看求解日志。参数说明路径分析有几个必调参数通过INAContext的属性设置参数设置方式说明阻抗属性naSolver.ImpedanceAttributeName用哪个字段当成本如 Length、Time是否允许 U 形转弯naSolver.UTurnPolicy默认不允许物流场景常要允许输出路径几何naSolver.OutputGeometryPrecision精度太高结果大一般 1 米够用停靠点顺序naSolver.FindBestSequence是否求解最优顺序TSP 场景要开ImpedanceAttributeName设错是最常见的翻车点。网络数据集里可能同时有 Length 和 DriveTime 两个成本字段设成 Length 算出来的是最短距离设成 DriveTime 才是最快时间。现象就是结果和预期对不上但代码不报错。注意Solve是同步阻塞的网络数据集大、停靠点多的时候会卡住界面。放在后台线程里跑用BackgroundWorker或Task别在主线程直接调。5. 避坑与排查那些让程序跑不起来的细节5.1 许可初始化失败报“没有许可”现象程序启动就抛异常提示许可状态是esriLicenseNotLicensed或esriLicenseUnavailable。原因三种可能。一是 ArcGIS License Manager 服务没启动二是防火墙拦了 27000 端口三是产品级别枚举选错了比如装的是 ArcView 却申请 ArcInfo。解决先开服务管理器确认ArcGIS License Manager在运行。再检查防火墙27000 端口要放行。最后核对esriLicenseProductCode枚举和实际授权是否匹配。热词里 arcgis安装license无法启动 基本就是这个链路。5.2 游标不释放文件被锁现象程序跑完gdb 或 shapefile 打不开提示“正在被其他程序使用”。原因IFeatureCursor、IWorkspace这些 COM 对象没释放进程还占着文件句柄。解决每个游标用完调Marshal.ReleaseComObject(cursor)工作空间用完调Marshal.ReleaseComObject(workspace)。更稳妥的做法是把这些操作包在try...finally里finally 里释放。别指望 GC 自动回收COM 对象的生命周期和 .NET 托管对象不是一回事。5.3 空间分析结果为空或范围异常现象Buffer 或 Clip 跑完输出要素类存在但里面没数据或者范围大得离谱。原因坐标系不一致。输入数据是地理坐标系度距离参数按米给结果要么小到看不见要么大到覆盖全球。解决分析前统一投影。用IGeometry.Project转到投影坐标系或者确保输入数据本身就是投影坐标。热词里 arcgis裁剪影像、arcgis做坡度图 遇到的结果异常先查坐标系。5.4 网络分析求解返回空路径现象停靠点加进去了Solve也执行了但 Routes 里没要素。原因停靠点不在网络数据集的可达范围内。网络数据集有连通性设置如果停靠点落在没有连通的边上求解器找不到路径。解决加停靠点前先做位置捕捉用INALocator把点吸附到最近的网络边上。另外检查网络数据集的连通性策略端点连通和任意折点连通结果差别很大。5.5 32 位进程内存溢出现象处理大数据量时程序崩溃报OutOfMemoryException。原因ArcObjects 是 32 位 COM进程内存上限约 2GB大数据量游标遍历很容易撑爆。解决分批处理用IQueryFilter加WhereClause分页读。或者改用 ArcGIS Pro SDK 走 64 位路线。这是 ArcObjects 的硬伤没有银弹。6. 进阶技巧把网络分析和业务数据串起来走到这一步单次路径求解已经不是问题了。真正有价值的是把网络分析和业务库联动做成一个能反复跑的服务。我一般会这么做用 C# 读业务库SQL Server 或 Access里的订单和车辆表动态生成停靠点跑完路径分析后把结果写回业务库。// 从业务库读订单生成停靠点 string connStr Data Source.;Initial CatalogLogistics;Integrated SecurityTrue; using (SqlConnection conn new SqlConnection(connStr)) { conn.Open(); SqlCommand cmd new SqlCommand( SELECT OrderId, Lon, Lat FROM Orders WHERE Status Pending, conn); SqlDataReader reader cmd.ExecuteReader(); while (reader.Read()) { IPoint pt new PointClass(); pt.PutCoords((double)reader[Lon], (double)reader[Lat]); // 用 pt 创建停靠点加到 naClass } }逻辑说明业务库的经纬度直接构造IPoint但注意坐标系要和网络数据集一致。如果网络数据集是投影坐标这里要先做坐标转换否则停靠点位置全错。参数说明PutCoords传的是 X经度和 Y纬度顺序别反。数据库连接串按实际环境改Access 用ProviderMicrosoft.ACE.OLEDB.12.0。一个我踩过的坑批量求解时每次Solve都新建NAContext会越来越慢因为网络数据集每次都要重新加载。正确做法是复用同一个NAContext只清空停靠点重新加。清空用naContext.Classes.get_ItemByName(Stops).FeatureClass.DeleteSearchedRows(null)。验证结果对不对我习惯用两个手段。一是把路径几何导出成 shp叠到底图上肉眼扫一遍二是对比阻抗值手动算一条已知路径的距离和求解器结果比误差在 5% 以内算正常。超过这个范围回去查阻抗属性设置和连通性。这套东西值不值得投入取决于你的业务里“路径”和“空间关系”出现的频率。如果每天要算几百条路径、或者编辑操作是重复性的那写一次代码省下的人力很可观。如果只是偶尔算一次ArcMap 手动点更快。我自己的习惯是任何要重复三次以上的空间操作就值得写成 C# 工具。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站