ArcGIS Pro 二次开发
本文基于 Windows7 + VS2019 + .NET Framework 4.8 + ArcGIS Pro 2.5.22081 开发和撰写。
开发环境配置
获取ArcGIS Pro
ArcGIS Pro可在Esri官网申请21天试用。
安装VS2019
VS2019的安装十分简单,在微软官网下载VS2019社区版安装程序,双击安装即可,具体可参考该博客
安装ArcGIS Pro SDK
关闭VS拓展自动更新
首先打开安装好的VS2019,点击“菜单栏-工具-选项”,在选项中找到“环境-拓展”,关闭拓展自动更新,如下图所示。关闭拓展自动更新可以防止拓展自动更新后与当前环境不匹配,如我的环境为ArcGIS Pro2.5,如果不关闭自动更新,则下次打开VS时ArcGIS Pro SDK插件将自动更新为2.6版本,与Pro版本不匹配,无法使用。
正式安装插件
接下来开始安装ArcGIS Pro SDK for .NET,需要点击“菜单栏-拓展-管理拓展”,在弹出的窗口中切换至联机,搜索“ArcGIS Pro”,找到“ArcGIS Pro SDK for .NET”和“ArcGIS Pro SDK for .NET(Utilities)”两个插件,安装并禁用自动更新。点击安装后,重启VS插件即安装完毕,至此,开发环境配置完成。
创建第一个Pro Add-in
使用模板创建Pro Add-in项目
打开VS2019,选择“创建新项目”,将“项目类型筛选”设置为“ArcGIS Pro SDK”,找到“ArcGIS Pro 模块加载项”创建项目即可,注意选择语言为C#而非VB。
添加一个button
Pro的插件及配置使用DAML文件,即项目下的“config.daml”进行声明。
手动添加button
添加button至显示
首先,我们来尝试手动添加一个button。打开“config.daml”文件,在controls标签下添加一个button标签。
<controls>
<button id="AddOneButton" caption="Add one button" className="AddOneButton" loadOnClick="false" smallImage="Images\AddInDesktop16.png" largeImage="Images\AddInDesktop32.png" keytip="AOB">
<tooltip>Add one button</tooltip>
</button>
</controls>
添加完button标签后,该控件并不会显示,只有当控件被某个group引用时,才会显示在菜单中,应用方式如下,其中refID为创建button标签时的id。
<groups>
<group id="DJ_SuspectTrackingSystem_Group1" caption="Group 1" appearsOnAddInTab="true">
<button refID="AddOneButton"/>
</group>
</groups>
至此,当Pro加载时即会在“菜单栏-加载项-Group”中显示该控件。修改完成后的“config.daml”文件和Pro中显示效果如下图所示。
为button添加逻辑代码
修改daml后,仅实现了在Pro中显示button,下面来为button添加逻辑代码。
在项目中新建一个类,类名为刚才daml文件中对应button的className属性,并使其继承自Pro SDK中的Button类。然后重写Button的相关方法,如点击时触发的OnClick方法,在其中实现逻辑代码即可,如下图。
自动添加button
在我们熟悉了daml文件之后,日常开发即可直接使用VS提供的快捷添加控件的方式。
在项目上“右击-添加-新建项”,在弹出的窗口左侧选择“ArcGIS Pro Add-ins”中进行筛选后,选择“ArcGIS Pro 按钮”,点击添加,VS即会自动添加一个button类至项目中,在daml文件的controls中添加button定义,并在默认group中引用该button。
生成Addin文件
插件配置完成后,在解决方案上“右键-重新生成解决方案”,待解决方案生成完毕后,在解决方案文件夹\bin\Debug
目录下找到*.esriAddinX
文件,该文件即为插件安装文件,双击即可为Pro安装该插件。
调试插件
如果不希望直接为Pro安装插件,而是在开发过程中需要测试插件效果,直接按快捷键F5或点击运行,VS将启动Pro,并在Pro中加载修改后的插件,可以在其中对插件进行测试。
开发小tip
- 当项目是从其他电脑拷贝而来时,引用地址可能不正确,此时,可以在解决方案上右击,找到“修复 Pro 引用”选项,点击后,插件会自动更新引用。若要手动更新引用,dll文件通常存放在
Pro安装路径\bin
和Pro安装路径\bin\Extensions
目录下。 - 提示"未能解析主引用***,因为它是针对“.NETFramework,Version=v4.8”框架生成的。该框架版本高于当前目标框架"错误信息,则说明生成使用的Framework版本与当前项目应该使用的Framework版本不匹配,在项目上“右击-属性-生成程序”,将“目标框架”切换为当前项目版本即可。
- 不知道什么原因,对dockpane UI的修改,需要进行以下操作才能生效:
- Pro中卸载该加载项
- 重新打开Pro,发现加载项没有再加载(必须重新再打开一次)
- 再解决方案上“右击-重新生成解决方案”
- 再次打开Pro,修改即生效
DAML配置
DAML是Desktop Application Markup Language的缩写。是ESRI基于XML标准自定义的UI配置文件。插件和配置的声明性部分是在DAML文件中定义的,其中包含了框架元素(主要是插件)的集合,还包括声明性部分(框架所需的信息,以便在适当的时候激活或创建相关的对象)。通过这种方式实现界面和功能的分离。
DAML介绍
具体的DAML介绍请查看DAML ID reference。以下仅介绍常用节点。
根节点
即ArcGIS标签下的节点,大多数情况下无需修改,使用默认即可,常用的有:
- defaultAssembly:该配置代表的插件所在的程序集名称。
- defaultNamespace:该配置代表的插件所在的命名空间名称。
AddInInfo节点
AddInInfo节点用于声明插件的相关信息,如名称、描述、图标等
modules节点
modules节点是最长访问的节点,插件元素的添加、描述等均在该节点下。modules节点可以包括的元素包括ribbon按钮、工具、画廊、组合框、编辑框、调色板和其他控件,以及应用程序窗格和对接窗格。
Pro 控件级别
Pro的控件级别从上到下分为Module-Tab-Group-Menu-Control,相互关系如下图所示。具体关系控件层级的概念请参考ProGuide。
- Tab
- Group
- Menu
- Control
一个原始的DAML文件如下图所示,开发时,先在controls标签下创建所有要使用的控件及其描述,然后在需要显示控件的group标签中引用对应的control即可。
将control在新tab中显示
默认情况下,control将添加至“菜单栏-加载项”中,如果需要在单独的Tab中显示,则需要在daml文件tabs标签下新建tab标签,并在其中添加对需要显示的group的引用,如下图。
常用DAML元素
下面只介绍常用的元素及其属性、方法等,各元素具体使用情景、属性、方法等请参见官方API文档。DAML中通常可以包括controls、categories、dockpanes、groups、menus、minitoolbars、panes、toolbars等等各种元素,具体元素可参见官方DAML ID Reference
控件control
控件常用属性
控件常用方法
控件常见方法有:
- OnClick():单击控件时触发
使用时,在控件类中重写对应的方法即可,如:
internal class AddOneButton : ArcGIS.Desktop.Framework.Contracts.Button
{
protected override void OnClick()
{
MessageBox.Show("Hello World");
}
}
常用控件
- button
- comboBox
- checkBox
- labelControl
- tool
停靠窗dockpane
dockpane类为停靠窗口类,其UI由对应的.xaml文件确定,逻辑代码由对应的.cs类文件实现。关于DockPane,具体可以参见ProGuide-Dockpanes。
双击xaml文件即可进入设计窗口,可以通过拖拽的方式将各种控件添加至dockpane界面中,可以通过可视化或代码方式设置控件和dockpane的各种属性。
自定义DockPane停靠位置
使用dock,dockWith,autoHide属性可以设置DockPane的初始停靠状态。
- Dock:该属性用于设置初始停靠状态,可选值包括:
- left
- right
- top
- bottom
- float
- group
- dockWith:该属性可以指定要相对停靠的DockPane。
地理处理GeoProcess
可参考ProSnippets-Geoprocessing和ProConcepts-Geoprocessing
功能实现
很多功能实现可参考ArcGIS Pro SDK community samples
在Addin中直接打开自建的工具箱
若想要实现,点击插件上的按钮,自动打开对应的自建工具箱或系统工具箱,需要重写按钮的OnClick()方法,在其中使用ArcGIS.Desktop.Core.Geoprocessing.OpenToolDialog(toolPath, param_values)
方法打开工具箱,示例如下。若想要不打开工具箱而直接执行工具,则使用ArcGIS.Desktop.Core.Geoprocessing.ExecuteToolAsync(toolPath,param_values)
方法异步执行工具。
如果要使用系统工具箱,则直接用工具箱名\工具名
调用即可,如
。如需使用自建工具箱,则使用工具箱路径\工具箱名(包括后缀)\工具名
调用,如@"E:\ArcGIS\MyProject\sixTool\sixTool.pyt\OpenHDFTool"
此外,不论是打开工具还是执行工具,都必须输入参数,且创建参数时必须至少有一个输入,否则虽然不会抛出语法错误,但是工具不能正常执行,原因未明。
internal class FactorsCorrelationAnalysis : Button
{
protected override void OnClick()
{
//创建工具参数
//工具必须有参数
string input_points = "";
var param_values = Geoprocessing.MakeValueArray(input_points); //创建参数时必须至少有一个输入,否则工具不会正常显示
//获取sixTools的绝对路径
string nowPath = System.Windows.Forms.Application.StartupPath; //获取启动程序的可执行文件所在的目录
string ArcGISPath = System.IO.Directory.GetParent(nowPath).FullName; //获取当前目录的父目录的绝对路径
string toolRelativePath = @"Resources\ArcToolBox\Scripts\sixTool.pyt\FactorsCorrelationAnalysisTool";
string toolPath = System.IO.Path.Combine(ArcGISPath, toolRelativePath);
//MessageBox.Show(toolPath);
//打开工具箱中的工具
Geoprocessing.OpenToolDialog(toolPath, param_values);//必须输入工具参数
}
}
点击弹出浮动窗口
若要实现点击按钮后弹出一个浮动窗口,如ArcGIS自带的查询工具,则在项目中添加一个Dockpane停靠窗类,并在“config.daml”文件中设置其“Dock”属性为“float”即可。
使用Python脚本
Pro中使用Python脚本,本质上就是通过cmd的方式,调用Pro对应的python解释器来执行脚本,并获取脚本执行结果。详细可参考官方sample CallScriptFromNet
//从环境变量中获取Pro对应的Python解释器的绝对路径
var pathProExe = System.IO.Path.GetDirectoryName((new System.Uri(Assembly.GetEntryAssembly().CodeBase)).AbsolutePath);
if (pathProExe == null) return;
pathProExe = Uri.UnescapeDataString(pathProExe);
pathProExe = System.IO.Path.Combine(pathProExe, @"Python\envs\arcgispro-py3");
System.Diagnostics.Debug.WriteLine(pathProExe);
var pathPython = System.IO.Path.GetDirectoryName((new System.Uri(Assembly.GetExecutingAssembly().CodeBase)).AbsolutePath);
if (pathPython == null) return;
pathPython = Uri.UnescapeDataString(pathPython);
System.Diagnostics.Debug.WriteLine(pathPython);
//使用cmd调用python解释器来执行python脚本
//创建用于执行cmd的字符串以及获取异常信息的对象
var myCommand = string.Format(@"/c """"{0}"" ""{1}""""",
System.IO.Path.Combine(pathProExe, "python.exe"),
System.IO.Path.Combine(pathPython, "test1.py"));
System.Diagnostics.Debug.WriteLine(myCommand);
var procStartInfo = new System.Diagnostics.ProcessStartInfo("cmd", myCommand);
procStartInfo.RedirectStandardOutput = true;
procStartInfo.RedirectStandardError = true;
procStartInfo.UseShellExecute = false;
procStartInfo.CreateNoWindow = true;
//开始执行脚本
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo = procStartInfo;
proc.Start();
//获取执行结果并显示
string result = proc.StandardOutput.ReadToEnd();
string error = proc.StandardError.ReadToEnd();
if (!string.IsNullOrEmpty(error)) result += string.Format("{0} Error: {1}", result, error);
System.Windows.MessageBox.Show(result);
创建要属类
创建要属类本质上是使用Toolbox中的创建要属类工具(CreateFeatureclass_management)
来创建所需的要属类。详细可参考官方sample ConstructingGeometries_CSharp
//根据输入的要属类名称和类型在默认数据库中创建要属类的函数
private static async Task CreateLayer(string featureclassName, string featureclassType)
{
//创建要素时的参数list
List<object> arguments = new List<object>
{
// store the results in the default geodatabase
CoreModule.CurrentProject.DefaultGeodatabasePath,
// name of the feature class
featureclassName,
// type of geometry
featureclassType,
// no template
"",
// no z values
"DISABLED",
// no m values
"DISABLED"
};
//异步,为参数list添加坐标系统参数
await QueuedTask.Run(() =>
{
// spatial reference
arguments.Add(SpatialReferenceBuilder.CreateSpatialReference(3857));
});
//异步执行创建要属类工具,创建要素类
IGPResult result = await Geoprocessing.ExecuteToolAsync("CreateFeatureclass_management", Geoprocessing.MakeValueArray(arguments.ToArray()));
}
}
为线要素类添加记录
执行的操作包括:
- 获取需要编辑的要属类
- 创建编辑器
- 创建一个MapPoint List,用于存储构建线记录的点
- 获取点要素类游标,迭代点要素类的所有记录,将构建线记录的点对象添加至MapPoint List对象中
- 使用PolylineBuilder.CreatePolyline()方法,基于MapPoint List对象构建Polyline对象
- 使用编辑器对象的Create()方法,基于Polyline对象为线要属类添加一条记录
- 执行编辑器操作,保存修改
- 完成
具体可参考官方sample ConstructingGeometries_CSharp
//为线要素类中添加记录的函数
//polylineLayer为需要添加记录的线要素图层;pointLayer为用于构建线要素的点图层,也可以执行构建点要素
private Task<bool> ConstructSamplePolylines(FeatureLayer polylineLayer, FeatureLayer pointLayer)
{
// ()=>{...}或()=>functionNmae() 为.NET3.0以后的新特性 Lambda表达式
// 也就是说,执行=>后面的函数,把函数返回值作为一个参数传给当前函数
// execute the fine grained API calls on the CIM main thread
return QueuedTask.Run(() =>
{
// get the underlying feature class for each layer
// as 和is都是强制类型转换运算符。作用类似于C中的 (type)data; 一般使用as,具体不深究
// 此处未将 polylineLayer.GetTable() 强制转换为 FeatureClass 类型后,赋值给 polylineFeatureClass 。
var polylineFeatureClass = polylineLayer.GetTable() as FeatureClass;
var pointFeatureClass = pointLayer.GetTable() as FeatureClass;
// retrieve the feature class schema information for the feature classes
var polylineDefinition = polylineFeatureClass.GetDefinition() as FeatureClassDefinition;
var pointDefinition = pointFeatureClass.GetDefinition() as FeatureClassDefinition;
// construct a cursor for all point features, since we want all feature there is no
// QueryFilter required
var pointCursor = pointFeatureClass.Search(null, false);
var is3D = pointFeatureClass.GetDefinition().HasZ();
// initialize a counter variable
int pointCounter = 0;
// initialize a list to hold 5 coordinates that are used as vertices for the polyline
var lineMapPoints = new List<MapPoint>(5);
// set up the edit operation for the feature creation
var createOperation = new EditOperation()
{
Name = "Create polylines",
SelectNewFeatures = false
};
// loop through the point features
while (pointCursor.MoveNext())
{
pointCounter++;
var pointFeature = pointCursor.Current as Feature;
// add the feature point geometry as a coordinate into the vertex list of the line
// - ensure that the projection of the point geometry is converted to match the spatial reference of the line
lineMapPoints.Add(((MapPoint)GeometryEngine.Instance.Project(pointFeature.GetShape(), polylineDefinition.GetSpatialReference())));
// for every 5 geometries, construct a new polyline and queue a feature create
if (pointCounter % 5 == 0)
{
// construct a new polyline by using the 5 point coordinate in the current list
var newPolyline = PolylineBuilder.CreatePolyline(lineMapPoints, polylineDefinition.GetSpatialReference());
// queue the create operation as part of the edit operation
createOperation.Create(polylineLayer, newPolyline);
// reset the list of coordinates
lineMapPoints = new List<MapPoint>(5);
}
}
// execute the edit (create) operation
return createOperation.ExecuteAsync();
});
}
待续
ArcGIS Pro SDK 本来不在我的近期学习计划中,只有由于朋友让帮忙做一个小插件所以稍微学了一点,使用上面介绍的东西就搞定了。因此,本系列下一次更新可能遥遥无期……(也说不定直接就太监了呢)
本文参考:
- 博客 https://blog.csdn.net/xiangqiang2015/article/details/81741689
- 博客 https://blog.csdn.net/DynastyRumble/article/details/104683339
- Esri官方wiki https://github.com/esri/arcgis-pro-sdk/wiki
- Pro API reference https://pro.arcgis.com/en/pro-app/sdk/api-reference/index.html#topic10500.html
- ArcGIS Pro DAML ID Reference https://github.com/Esri/arcgis-pro-sdk/wiki/ArcGIS-Pro-DAML-ID-Reference
- ArcGIS Pro Addin guide https://github.com/Esri/arcgis-pro-sdk/wiki/ProGuide-Build-Your-First-Add-in
- ArcGIS Pro SDK 社区示例 https://github.com/Esri/arcgis-pro-sdk-community-samples
ArcGIS Pro 二次开发的更多相关文章
- Skyline 7 版本TerraExplorer Pro二次开发快速入门
年底了,给大家整理了一下Skyline 7版本的二次开发学习初级入门教程,献给那些喜欢学习的年轻朋友. 我这整理的是Web控件版本的开发示例,里面页面代码保存成html,都可以直接运行的. 测试使用的 ...
- Skyline Te Pro二次开发技能总结
前两天项目开发中,忽然一个Imagelabel的参数不会调了,但是前段时间可是很熟悉的.好吧,好记性不如烂笔头! 1. 模型弹出窗调试 这里的模型弹出框指涉及到模型操作的,比如监听模型选定事件.根据窗 ...
- 关于ArcGis的二次开发-基于ArcEngine10.2(内有安装包)
网上很少有arcgis engine10.2的安装包,在这里我把安装包链接附上,是百度云,有需要的可以自己下--http://pan.baidu.com/s/1mhIhYYG 顺带着把arcgis d ...
- Arcgis runtime sdk .net 二次开发
前段时间研究了下 arcgis runtime sdk .net 二次开发··这里做个笔记 runtime版本为100.6 基于WPF 开发 命名空间引入 xmlns:esri="http: ...
- ArcGIS Pro Add-In插件开发[ArcGIS Pro SDK for .NET]
本文基于 Windows7 + VS2019 + .NET Framework 4.8 + ArcGIS Pro 2.5 开发和撰写. 目录 开发环境配置 获取ArcGIS Pro 安装VS2019 ...
- 【ArcGIS二次开发】CreateFeature报错(HRESULT E_FAIL)
在VS2010下基于ArcGIS 10.1做二次开发时遇到个奇怪的问题,对于MXD工程文档中已经存在的图层,获取其FeatureClass可以调用CreateFeature()函数生成要素,但是对于通 ...
- ArcGIS二次开发AO软件安装破解教程
最近在做ArcGIS二次开发时,采用C#中的WPF技术,在调研中发现ArcGIS 10.3及以上版本支持WPF技术,但是关于ArcGIS10.3的破解教程甚少,自己尝试了不少方法都失败了,淘@宝@商家 ...
- ArcGIS Pro开发Web3D应用(3)——Server/Portal授权服务开发
1.整体环境搭建完成 WebAdaptor.DataStore.Portal for arcgis.arcgis server.arcgis pro都成功部署安装,不管是同服务器还是不同服务器,最好做 ...
- ArcGIS Pro开发Web3D应用(2)——地图分屏对比(多屏对比)思路
很多应用中都需要用到地图联动.多屏对比.二三维分屏.大屏显示,有图形可视化的地方就有事件响应触发:鼠标按下.移动.鼠标滚轮,由此触发了地图上坐标或范围的变化,将这些变化发送给另一个地图并响应这些变化, ...
随机推荐
- idea中运行Tomcat后控制台出现乱码(统一设置成UTF-8)
出现问题:运行Tomcat后控制台出现乱码,输出语句乱码(idea 2019.3版本) 解决方法: 方案1:File----->Settings..----->Editor-----> ...
- ios 生成字母加数字的随机数
文章来自:http://blog.csdn.net/baidu_25743639/article/details/73801700 近期项目第三方登录之后默认创建账号和密码,就用随机数生产,这里只需要 ...
- 分享一个内网穿透工具frp
首先简单介绍一下内网穿透: 内网穿透:通过公网,访问局域网里的IP地址与端口,这需要将局域网里的电脑端口映射到公网的端口上:这就需要用到反向代理,即在公网服务器上必须运行一个服务程序,然后在局域网中需 ...
- 学生成绩管理系统-JAVA语言测试
首先右键新建一个工程project 选择Java Project,单击next下一步 project命名为“学生成绩管理系统”,点击finish继续 右键src文件夹新建Package包,取名为te ...
- URLDecoder异常解决方法
URLDecoder对参数进行解码时候,代码如: URLDecoder.decode(param,"utf-8"); 有时候会出现类似如下的错误: URLDecoder异常Ille ...
- 通过java程序(JSch)运行远程linux主机上的shell脚本
如果您看完文章之后,觉得对您有帮助,请帮我点个赞,您的支持是我不竭的创作动力! 如果您看完文章之后,觉得对您有帮助,请帮我点个赞,您的支持是我不竭的创作动力! 如果您看完文章之后,觉得对您有帮助,请帮 ...
- FSAF
Feature Selective Anchor-Free Module for Single-Shot Object Detection https://zhuanlan.zhihu.com/p/5 ...
- 使用JSPWiki丰富Unity-UPM包的使用
1.简述 诸如npm.Nuget之类的包管理工具,Unity推出了自己的Unity Package Manager(UPM)工具来管理使用到的第三方库. 现在Unity Package Manager ...
- .NET Core 微服务—API网关(Ocelot) 教程 [四]
前言: 上一篇 介绍了Ocelot网关和认证服务的结合使用,本篇继续介绍Ocelot相关请求聚合和Ocelot限流 一.请求聚合 Ocelot允许声明聚合路由,这样可以把多个正常的Routes打包并映 ...
- JavaFX桌面应用-为什么应用老是“未响应”
日常使用软件的过程中,偶尔会遇到软件突然卡住,再点击几次就变成"未响应"的情况. 在JavaFX应用中同样也会出现这种情况,在开发过程中应该尽量避免这种情况的出现. >> ...