> 文章列表 > 【ArcGIS Pro二次开发】(23):用地编码和用地名称的规范性检查

【ArcGIS Pro二次开发】(23):用地编码和用地名称的规范性检查

【ArcGIS Pro二次开发】(23):用地编码和用地名称的规范性检查

在国空或村庄规划的编制过程中,随着规划用地的调整,经常会手动修改用地编码和用地名称,不可避免的会出现错误,如果单靠人工校对,累人又不能保证准确性。这个工具的目的就是检查用地编码和用地名称是否规范,二者是否一一对应。


一、要实现的功能

如上图所示,右键点击地图中的要素图层,点击【检查用地用海字段】按钮,打开工具框,选择图层的用地编码字段和用地名称字段,点击运行即可。

运行结果如下图:

要素会新增一个【用地用海检查】字段,用地编码和用地名称的规范性错误会列在字段里。


二、实现流程

创建ProWindow工具框等基础功能可以参看往期文章,这里只把实现核心功能的流程列举出来。

1、通过嵌入的Excel资源文件获取用地用海分类

在往期的文章用到一种方法,使用【字典(Dictionary)创建表格(Table)】来获取用地用海分类。这个方法有点麻烦,需要编辑字典,遇上复杂的表格不好操作。

这里采用另一个方法,使用嵌入式的文件的方式,直接从Excel文件中读取。

首先需要将Excel文件的生成操作设置为【嵌入的资源】,然后从资源中读取。

我这里不采用直接读取的方式,为了保险一点(可能没有必要),先把资源里的文件复制到本地,再从本地读取,代码如下:

            // 复制资源文件string folder = Project.Current.HomeFolderPath;string excelPath = @"用地用海_DM_to_MC.xlsx";string outputPath = System.IO.Path.Combine(folder, excelPath);  string resourceName = @"CheckFieldYDYH." + excelPath;    // 获取当前程序集的实例Assembly assembly = Assembly.GetExecutingAssembly();// 从嵌入资源中读取文件using (Stream stream = assembly.GetManifestResourceStream(resourceName)){// 创建目标文件using (FileStream fileStream = new FileStream(filePath, FileMode.Create)){// 将文件从嵌入资源复制到目标文件stream.CopyTo(outputPath );}}

在这个案例中,我们要读取Excel文件的内容是第一列和第二列的值,并将其输出成一个字典(Dictionary)即可。

代码如下:

            // 建立 Excel 应用程序对象Microsoft.Office.Interop.Excel.Application excelApp = new Microsoft.Office.Interop.Excel.Application();// 打开 Excel 文件Workbook workbook = excelApp.Workbooks.Open(excelPath);// 获取工作表Worksheet worksheet = workbook.Worksheets[1];// 定义字典Dictionary<string, string> dict = new Dictionary<string, string>();// 获取Excel表格中的数据for (int row = 1; row <= worksheet.UsedRange.Rows.Count; row++){string key = worksheet.Cells[row, col1].Value.ToString();string value = worksheet.Cells[row, col2].Value.ToString();dict.Add(key, value);}//  保存并关闭 Excel 文件和应用程序对象workbook.Close(true);excelApp.Quit();

至此,就实现了从Excel资源文件中读取数据并输出为字典(Dictionary)。

2、将目标字段值中的空值【null】转换为【空字符串】

下一步正常就该开始编辑属性表,但为了保证数据计算安全,这里再做了一件事,将2个目标字段值中的空值【null】转换为【空字符串】,这也是被空值坑过多次之后,我现在几乎都会做这个预处理。代码如下:

            // 获取所选图层的所有字段var fields = await QueuedTask.Run(() =>{return initlayer.GetFieldDescriptions();});// 使用异步任务在后台进行编辑操作await QueuedTask.Run(() =>{// 打开要素图层的表格var table = initlayer.GetTable();// 定位到属性表的游标using (var tableCursor = table.Search(null, false)){while (tableCursor.MoveNext()){// 获取当前记录的值var row = tableCursor.Current;// 历数所有字段foreach (var field in fields){// 排除不可编辑的字段if (field.IsReadOnly == false){// 如果是字符串类型,则进行下一步if (field.Type == FieldType.String){var currentValue = row[field.Name];if (currentValue is null){currentValue = "";}// 更新该字段的值row[field.Name] = currentValue;row.Store(); // 保存修改}}}}}});

3、新建检查字段,并通过属性表编辑计算字段值

新建一个【用地用海检查】字段,打开当前选择的的要素图层的属性表进行编辑。

计算逻辑如下:

1)分别针对2个字段,通过【new List<string>(dict.Keys).Contains(bm)】判断该字段值是否在用地用海分类的规范命名范围内,如果不在范围内,刚输出错误信息。

2)如果2个字段都满足规范,则通过【dict[bm.ToString()] != mc.ToString()】判断用地编码和用地名称是否一一对应,如果有误,则输出错误信息。

3)最后给【用地用海检查】字段赋值即可。

            // 使用异步任务在后台进行编辑操作await QueuedTask.Run(() =>{// 打开要素图层的表格var table = initlayer.GetTable();// 定位到属性表的游标using (var tableCursor = table.Search(null, false)){while (tableCursor.MoveNext()){// 获取当前记录的值var row = tableCursor.Current;var bm = row[bm_field];var mc = row[mc_field];// 定义错误信息文字string err = "";// 设置一个flag:是否符合规范bool isOK = true;// 检查编码字段if (new List<string>(dict.Keys).Contains(bm) == false){err += "BM错误;";isOK = false;}// 检查名称字段if (new List<string>(dict.Values).Contains(mc) == false){err += "MC错误;";isOK = false;}// 检查编码和名称是否一一对应if (isOK){if (dict[bm.ToString()] != mc.ToString()){err += "BM和MC不匹配";}}// 检查字段赋值row["用地用海检查"] = err;row.Store();}this.Close();MessageBox.Show("字段值更新完成!");}});

三、工程文件分享

 最后,放上工程文件的链接:

CheckFieldYDYHhttps://pan.baidu.com/s/1aumM78dtntI5an6HVl3owg?pwd=i3qd

PS:可以直接点击...bin\\Debug\\net6.0-windows\\下的.esriAddinX文件直接安装。