在国空或村庄规划的编制过程中,随着规划用地的调整,经常会手动修改用地编码和用地名称,不可避免的会出现错误,如果单靠人工校对,累人又不能保证准确性。这个工具的目的就是检查用地编码和用地名称是否规范,二者是否一一对应。
一、要实现的功能
如上图所示,右键点击地图中的要素图层,点击【检查用地用海字段】按钮,打开工具框,选择图层的用地编码字段和用地名称字段,点击运行即可。
运行结果如下图:
要素会新增一个【用地用海检查】字段,用地编码和用地名称的规范性错误会列在字段里。
二、实现流程
创建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文件直接安装。