在国土空间规划中,用地用海分类采用三级分类体系,共设置24种一级类、106种二级类及39 种三级类。在某些场景中,需要按等级归类并汇总统计。
这个小工具的作用就是通过用地编码生成三级地类,作为后续统计的基础。
一、要实现的功能
如上图所示,右键点击地图中的要素图层,点击【生成分级用地用海】按钮,打开工具框,选择图层的用地编码字段、分级类型和是否生成名称,点击运行即可。
其中分级类型中,如果选【大类】,会生成新字段【大类编码】;选【中类】,则会生成新字段【大类编码、中类编码】,以此类推。
如果勾选【是否生成用地用海名称】,则会根据编码字段,生成名称字段。
例如,你选择【中类】,并勾选【是否生成用地用海名称】,要素图层会新生成【大类编码、大类名称、中类编码、中类名称】4个字段,并分别计算它们的字段值。
运行结果如下图:
二、实现流程
1、创建ProWindow工具框并设置参数框的内容
创建一个ProWindow工具框,具体做法参看之前的文章:
【ArcGIS Pro二次开发】(13):ProWindow的用法
将当前选择的要素图层加入参数框:
// 获取当前选择的要素图层
FeatureLayer initlayer = MapView.Active.GetSelectedLayers().FirstOrDefault() as FeatureLayer;
// combox_fc框中添加当前选择的要素图层
combox_fc.Items.Add(initlayer);
combox_fc.SelectedIndex = 0;
将当前选择要素图层的所有字段添加到combox中,以用于手动选择字段:
// 清空combox_field
cb.Items.Clear();
await QueuedTask.Run(async () =>
{
// 获取所选图层的所有字段
var fields = initlayer.GetFieldDescriptions();
foreach (var field in fields)
{
await QueuedTask.Run(() =>
{
// 在UI线程上执行添加item的操作
Application.Current.Dispatcher.Invoke(() =>
{
// 将所有字段名添加到combox_field中
cb.Items.Add(field.Name);
});
});
}
});
用地用海分级中加入3种模式,并将其中1种设为默认:
// combox_model框中添加3种模式,默认【大类】
combox_model.Items.Add("大类");
combox_model.Items.Add("中类");
combox_model.Items.Add("小类");
combox_model.SelectedIndex = 0;
2、主要流程代码
这里我把工作的主要流程整理了一下,将其中部分会重复使用的代码写成方法,这样看上去流程会更加清晰:
// 参数获取
string fcPath = combox_fc.Text;
string bmField = combox_field.Text;
// 模式转换
int model = 1;
if (combox_model.Text == "中类") { model = 2; }
else if (combox_model.Text == "小类") { model = 3; }
// 根据需求生成三级用地编码和名称
if (model >= 1)
{
AddField(fcPath, "大类编码", "TEXT"); // 添加大类编码
GetBM1(fcPath, bmField, "大类编码"); // 计算大类编码
if (checkbox_isMC.IsChecked == true)
{
AddField(fcPath, "大类名称", "TEXT"); // 添加大类名称
YDYHChange(fcPath, "大类编码", "大类名称"); // 编码转名称
}
}
if (model >= 2)
{
AddField(fcPath, "中类编码", "TEXT"); // 添加中类编码
GetBM2(fcPath, bmField, "中类编码"); // 计算中类编码
if (checkbox_isMC.IsChecked == true)
{
AddField(fcPath, "中类名称", "TEXT"); // 添加中类名称
YDYHChange(fcPath, "中类编码", "中类名称"); // 编码转名称
}
}
if (model >= 3)
{
AddField(fcPath, "小类编码", "TEXT"); // 添加小类编码
GetBM3(fcPath, bmField, "小类编码"); // 计算小类编码
if (checkbox_isMC.IsChecked == true)
{
AddField(fcPath, "小类名称", "TEXT"); // 添加小类名称
YDYHChange(fcPath, "小类编码", "小类名称"); // 编码转名称
}
}
流程比较清晰(只是水平有限,这多重if确实挺难看的),根据【分级类型】和【是否生成用地用海名称】来判断生成的新字段,并进行计算。
在此之前,将分级类型转成整型方便判断。
整合的方法包括【添加字段、计算各级用地编码字段、通过用地用海转换实现编码转名称】。
3、【添加字段】
添加字段比较简单,调用一下GP工具就可以了:
var par_AddField = Geoprocessing.MakeValueArray(fcPath, fieldName, fieldType, null, null, fieldLength, fieldAlias, null, null, null);
await QueuedTask.Run(() => Geoprocessing.ExecuteToolAsync("management.AddField", par_AddField, null, null, null, executeFlags));
4、【计算各级用地编码字段】
计算字段主要通过打开要素图层的属性表并进行编辑来实现,之前有写过这方面的内容,可以复习一下:
【ArcGIS Pro二次开发】(10):属性表字段(field)的修改
以提取编码大类为例,通过Substring()方法提取前2位文字,主要代码如下:
await QueuedTask.Run(() =>
{
// 打开要素图层的表格
var table = initlayer.GetTable();
// 定位到属性表的游标
using (var tableCursor = table.Search(null, false))
{
while (tableCursor.MoveNext())
{
// 获取当前记录的值
var row = tableCursor.Current;
string currentValue = row[fieldBefore] as string;
// 获取fieldBefore字段值的前两位
string newValue = currentValue.Substring(0, 2);
// 更新字段值
row[fieldAfter] = newValue;
row.Store();
}
}
});
提取中类和小类则再复杂一点,加个if判断一下即可:
// 取值默认为空
string newValue = "";
// 如果原字段值超过4位,获取fieldBefore字段值的前4位
if (currentValue.Length >= 4)
{
newValue = currentValue.Substring(0, 4);
}
5、【通过用地用海转换实现编码转名称】
这部分我已经专门发过文章,并且已经做成工具,直接使用即可:
【ArcGIS Pro二次开发】(15):用地用海名称和代码互转
简单就可实现用地编码转换为用地名称。
PS:综上,整个工具的代码量虽然算比较多,但其实大部分都在之前文章中写过,我把之前的一些方法都写到一个.cs文件中,基本就是引用即可。
因此本文中很多代码没有放出来,不过文章末尾会提供工程文件下载,可以自行查看全部代码。
如果你是新手,并且没看过我之前的相关文章,建议按上面的链接好好回看一下,不然可能会看得云里雾里。
三、工程文件分享
最后,放上工程文件的链接:
CreateGdYDYHhttps://pan.baidu.com/s/1BPvmCxWGCJqg_9UOnj30Pw?pwd=sz4b
PS:可以直接点击...bin\Debug\net6.0-windows\下的.esriAddinX文件直接安装。