ArcGIS Pro 3.4 二次开发 - 框架

环境:ArcGIS Pro SDK 3.4 + .NET 8

框架

1 框架

1.1 如何在 DockPane 可见或隐藏时订阅和取消订阅事件

private SubscriptionToken _eventToken = null;
// 当 DockPane 的可见性发生变化时调用。
protected override void OnShow(bool isVisible)
{
if (isVisible && _eventToken == null) // 当 dockpane 可见时订阅事件
{
_eventToken = MapSelectionChangedEvent.Subscribe(OnMapSelectionChangedEvent);
}
if (!isVisible && _eventToken != null) // 当 dockpane 关闭时取消订阅
{
MapSelectionChangedEvent.Unsubscribe(_eventToken);
_eventToken = null;
}
}
// 当 MapSelection 事件触发时的事件处理程序。
private void OnMapSelectionChangedEvent(MapSelectionChangedEventArgs obj)
{
MessageBox.Show("选择已更改");
}

1.2 执行命令

IPlugInWrapper wrapper = FrameworkApplication.GetPlugInWrapper("esri_editing_ShowAttributes"); // 获取插件包装器
var command = wrapper as ICommand; // 将插件包装器转换为ICommand接口,工具和命令(按钮)支持此接口
if ((command != null) && command.CanExecute(null)) // 检查命令是否可执行
command.Execute(null); // 执行命令

1.3 设置当前工具

// 使用 SetCurrentToolAsync 方法设置当前工具
FrameworkApplication.SetCurrentToolAsync("esri_mapping_selectByRectangleTool");
// 或者使用 ICommand.Execute 方法设置当前工具
ICommand cmd = FrameworkApplication.GetPlugInWrapper("esri_mapping_selectByRectangleTool") as ICommand;
if ((cmd != null) && cmd.CanExecute(null))
cmd.Execute(null);

1.4 激活选项卡

// 激活名为 "esri_mapping_insertTab" 的选项卡
FrameworkApplication.ActivateTab("esri_mapping_insertTab");

1.5 激活/停用状态 - 修改条件

// 根据状态在DAML文件中定义条件
if (activate)
FrameworkApplication.State.Activate("someState"); // 激活某个状态
else
FrameworkApplication.State.Deactivate("someState"); // 停用某个状态

1.6 判断应用程序是否繁忙

// 如果主工作线程上当前有任务正在运行,或者任何窗格或停靠窗格报告其处于繁忙或初始化状态,则认为应用程序繁忙。
// 许多 Pro 样式(如 Esri_SimpleButton)确保当 FrameworkApplication.IsBusy 为 true 时,按钮被禁用。
// 您可以使用此属性绑定到停靠窗格或窗格上控件(如列表框)的 IsEnabled 属性,以便在应用程序繁忙时禁用用户交互。
bool isbusy = FrameworkApplication.IsBusy;

1.7 获取应用程序主窗口

System.Windows.Window window = FrameworkApplication.Current.MainWindow;
// 将窗口居中
Rect rect = System.Windows.SystemParameters.WorkArea;
FrameworkApplication.Current.MainWindow.Left = rect.Left + (rect.Width - FrameworkApplication.Current.MainWindow.ActualWidth) / 2;
FrameworkApplication.Current.MainWindow.Top = rect.Top + (rect.Height - FrameworkApplication.Current.MainWindow.ActualHeight) / 2;

1.8 关闭 ArcGIS Pro

FrameworkApplication.Close(); // 关闭 ArcGIS Pro 应用程序

1.9 获取 ArcGIS Pro 版本

// "GetEntryAssembly" 应该返回 ArcGISPro.exe
string version = System.Reflection.Assembly.GetEntryAssembly()
.GetName().Version.ToString();

1.10 关闭特定窗格

string _viewPaneID = "my pane"; // 你的窗格的DAML ID
// 你可能会有多个窗格实例(InstanceIDs)。
// 因此你可以遍历所有窗格,只获取“你的”窗格
IList<uint> myPaneInstanceIDs = new List<uint>();
foreach (Pane pane in FrameworkApplication.Panes)
{
if (pane.ContentID == _viewPaneID)
{
myPaneInstanceIDs.Add(pane.InstanceID); // 你的窗格的InstanceID,可能有多个,所以构建集合
}
}
foreach (var instanceID in myPaneInstanceIDs) // 关闭每一个“你的”窗格。
{
FrameworkApplication.Panes.ClosePane(instanceID);
}

1.11 激活一个窗格

// 获取所有地图窗格
var mapPanes = ProApp.Panes.OfType<IMapPane>();
// 遍历每个地图窗格
foreach (Pane pane in mapPanes)
{
    // 检查窗格的标题是否为"MyMap"
    if (pane.Caption == "MyMap")
    {
        // 激活该窗格
        pane.Activate();
        // 退出循环
        break;
    }
}

1.12 ProWindow 在屏幕上的位置

ProWindow1 _prowindow1 = null;
{
double left = 150; //窗口的左边缘,相对于桌面
double top = 150; //窗口的顶部边缘,相对于桌面
//窗口是否已经打开?
if (_prowindow1 != null)
return;
_prowindow1 = new ProWindow1(left, top); //创建窗口
_prowindow1.Owner = FrameworkApplication.Current.MainWindow;
_prowindow1.Closed += (o, e) => { _prowindow1 = null; };
//除非将 SaveWindowPosition 设置为 false,否则 MetroWindows 会记住它们最后的位置。
_prowindow1.SaveWindowPosition = false; //设置为 false 以覆盖最后的位置
_prowindow1.Show();
//取消注释以模态方式显示
//_prowindow1.ShowDialog();
}

1.13 获取当前已安装插件的相关信息

var addin_infos = FrameworkApplication.GetAddInInfos(); // 获取所有已安装插件的信息
StringBuilder sb = new StringBuilder(); // 创建一个StringBuilder对象用于拼接字符串
foreach (var info in addin_infos) // 遍历每个插件的信息
{
if (info == null)
break; // 如果没有插件信息,则退出循环
sb.AppendLine($"Addin: {info.Name}"); // 添加插件名称
sb.AppendLine($"Description {info.Description}"); // 添加插件描述
sb.AppendLine($"ImagePath {info.ImagePath}"); // 添加插件图片路径
sb.AppendLine($"Author {info.Author}"); // 添加插件作者
sb.AppendLine($"Company {info.Company}"); // 添加插件公司
sb.AppendLine($"Date {info.Date}"); // 添加插件日期
sb.AppendLine($"Version {info.Version}"); // 添加插件版本
sb.AppendLine($"FullPath {info.FullPath}"); // 添加插件完整路径
sb.AppendLine($"DigitalSignature {info.DigitalSignature}"); // 添加插件数字签名
sb.AppendLine($"IsCompatible {info.IsCompatible}"); // 添加插件兼容性信息
sb.AppendLine($"IsDeleted {info.IsDeleted}"); // 添加插件是否已删除
sb.AppendLine($"TargetVersion {info.TargetVersion}"); // 添加插件目标版本
sb.AppendLine($"ErrorMsg {info.ErrorMsg}"); // 添加插件错误信息
sb.AppendLine($"ID {info.ID}"); // 添加插件ID
sb.AppendLine(""); // 添加空行分隔不同插件的信息
}
System.Diagnostics.Debug.WriteLine(sb.ToString()); // 在调试窗口输出插件信息
MessageBox.Show(sb.ToString(), "Addin Infos"); // 弹出对话框显示插件信息

1.14 查找一个停靠面板

// 为了查找一个停靠面板,你需要知道它的DAML ID
var pane = FrameworkApplication.DockPaneManager.Find("esri_core_ProjectDockPane");

1.15 停靠面板属性和方法

// 为了找到停靠面板,你需要知道它的DAML id
var pane = FrameworkApplication.DockPaneManager.Find("esri_core_ProjectDockPane");
// 确定可见性
bool visible = pane.IsVisible;
// 激活它
pane.Activate();
// 确定停靠面板状态
DockPaneState state = pane.DockState;
// 固定它
pane.Pin();
// 隐藏它
pane.Hide();

1.16 停靠面板的撤销/重做

// 为了找到一个停靠面板,你需要知道它的DAML id
var pane = FrameworkApplication.DockPaneManager.Find("esri_core_contentsDockPane");
// 获取操作管理器
OperationManager manager = pane.OperationManager;
if (manager != null)
{
// 撤销一个操作
if (manager.CanUndo)
await manager.UndoAsync();
// 重做一个操作
if (manager.CanRedo)
await manager.RedoAsync();
// 清除特定类别的撤销和重做操作栈
manager.ClearUndoCategory("Some category");
manager.ClearRedoCategory("Some category");
}

1.17 查找一个停靠面板并获取其 ViewModel

// 为了找到一个停靠面板,你需要知道它的 DAML id。
// 下面是一个定义了停靠面板的 DAML 示例。一旦找到停靠面板,你可以将其转换为
// 由 className 属性定义的停靠面板 ViewModel。
//
//<dockPanes>
//  <dockPane id="MySample_Dockpane" caption="Dockpane 1" className="Dockpane1ViewModel" dock="bottom" height="5">
//    <content className="Dockpane1View" />
//  </dockPane>
//</dockPanes>
Dockpane1ViewModel vm = FrameworkApplication.DockPaneManager.Find("MySample_Dockpane") as Dockpane1ViewModel;

1.18 打开后台选项卡

// 打开后台到“关于 ArcGIS Pro”选项卡。
FrameworkApplication.OpenBackstage("esri_core_aboutTab");

1.19 访问当前主题

//获取应用程序的主题
var theme = FrameworkApplication.ApplicationTheme;
//ApplicationTheme 枚举
if (FrameworkApplication.ApplicationTheme == ApplicationTheme.Dark)
{
//暗色主题
}
if (FrameworkApplication.ApplicationTheme == ApplicationTheme.HighContrast)
{
//高对比度主题
}
if (FrameworkApplication.ApplicationTheme == ApplicationTheme.Default)
{
//亮色/默认主题
}

1.20 显示一个Pro消息框

ArcGIS.Desktop.Framework.Dialogs.MessageBox.Show("Some Message", "Some title", MessageBoxButton.YesNo, MessageBoxImage.Information, MessageBoxResult.Yes);
// 显示一个消息框,包含消息内容、标题、按钮类型(是/否)、图标类型(信息)和默认按钮(是)

1.21 添加一个Toast通知

Notification notification = new Notification(); // 创建一个新的通知对象
notification.Title = FrameworkApplication.Title; // 设置通知的标题为应用程序的标题
notification.Message = "Notification 1"; // 设置通知的消息内容
notification.ImageSource = System.Windows.Application.Current.Resources["ToastLicensing32"] as ImageSource; // 设置通知的图标资源
ArcGIS.Desktop.Framework.FrameworkApplication.AddNotification(notification); // 将通知添加到应用程序中

1.22 更改按钮的标题或图像

private void ChangeCaptionImage()
{
IPlugInWrapper wrapper = FrameworkApplication.GetPlugInWrapper("MyAddin_MyCustomButton");
if (wrapper != null)
{
wrapper.Caption = "new caption"; // 设置按钮的新标题
// 确保在插件的 images 文件夹中包含 T-Rex16 和 T-Rex32 图片,并且设置
// BuildAction = Resource 和 Copy to OutputDirectory = Do not copy
wrapper.SmallImage = BuildImage("T-Rex16.png"); // 设置按钮的小图标
wrapper.LargeImage = BuildImage("T-Rex32.png"); // 设置按钮的大图标
}
}
private ImageSource BuildImage(string imageName)
{
return new BitmapImage(PackUriForResource(imageName)); // 根据图片名称构建 ImageSource
}
private Uri PackUriForResource(string resourceName)
{
string asm = System.IO.Path.GetFileNameWithoutExtension(
System.Reflection.Assembly.GetExecutingAssembly().Location); // 获取当前程序集名称
return new Uri(string.Format("pack://application:,,,/{0};component/Images/{1}", asm, resourceName), UriKind.Absolute); // 构建资源 URI
}

1.23 获取按钮的工具提示标题

// 传入你的按钮的daml id。或者传入任何Pro按钮的ID。
IPlugInWrapper wrapper = FrameworkApplication.GetPlugInWrapper("button_id_from daml");
var buttonTooltipHeading = wrapper.TooltipHeading;

1.24 订阅活动工具更改事件

private void SubscribeEvent()
{
    // 订阅活动工具更改事件
    ArcGIS.Desktop.Framework.Events.ActiveToolChangedEvent.Subscribe(OnActiveToolChanged);
}
private void UnSubscribeEvent()
{
    // 取消订阅活动工具更改事件
    ArcGIS.Desktop.Framework.Events.ActiveToolChangedEvent.Unsubscribe(OnActiveToolChanged);
}
private void OnActiveToolChanged(ArcGIS.Desktop.Framework.Events.ToolEventArgs args)
{
    // 获取前一个工具的ID
    string prevTool = args.PreviousID;
    // 获取当前工具的ID
    string newTool = args.CurrentID;
}

1.25 进度器 - 简单且不可取消

public async Task Progressor_NonCancelable()
{
    // 创建一个不可取消的进度器源,并设置进度消息
    ArcGIS.Desktop.Framework.Threading.Tasks.ProgressorSource ps = new ArcGIS.Desktop.Framework.Threading.Tasks.ProgressorSource("Doing my thing...", false);
    int numSecondsDelay = 5;
    // 如果在调试器中运行此代码,将不会看到进度对话框
    await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() => Task.Delay(numSecondsDelay * 1000).Wait(), ps.Progressor);
}

1.26 进度条 - 可取消

public async Task Progressor_Cancelable()
{
// 创建一个可取消的进度条源,标题为 "Doing my thing - cancelable",取消时的消息为 "Canceled"
ArcGIS.Desktop.Framework.Threading.Tasks.CancelableProgressorSource cps =
new ArcGIS.Desktop.Framework.Threading.Tasks.CancelableProgressorSource("Doing my thing - cancelable", "Canceled");
int numSecondsDelay = 5;
// 如果在调试器中运行此代码,将不会看到对话框
// 模拟一些可以取消的工作
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
// 设置进度条的最大值为延迟的秒数
cps.Progressor.Max = (uint)numSecondsDelay;
// 每秒检查一次
while (!cps.Progressor.CancellationToken.IsCancellationRequested)
{
// 增加进度条的值
cps.Progressor.Value += 1;
// 更新进度条的状态和消息
cps.Progressor.Status = "Status " + cps.Progressor.Value;
cps.Progressor.Message = "Message " + cps.Progressor.Value;
// 如果调试器已附加,输出当前循环的值
if (System.Diagnostics.Debugger.IsAttached)
{
System.Diagnostics.Debug.WriteLine(string.Format("RunCancelableProgress Loop{0}", cps.Progressor.Value));
}
// 如果进度条的值达到最大值,退出循环
if (cps.Progressor.Value == cps.Progressor.Max) break;
// 阻塞当前线程一秒钟
Task.Delay(1000).Wait();
}
// 输出是否已取消的信息
System.Diagnostics.Debug.WriteLine(string.Format("RunCancelableProgress: Canceled {0}",
cps.Progressor.CancellationToken.IsCancellationRequested));
}, cps.Progressor);
}

1.27 自定义按钮或工具的 disabledText 属性

//在 config.daml 中将工具的 loadOnClick 属性设置为 "false"。
//这将允许工具在 Pro 启动时创建,以便 disabledText 属性可以在启动时显示自定义文本。
//从工具中移除 "condition" 属性。使用 OnUpdate 方法(如下)来设置工具的启用/禁用状态。
//将 OnUpdate 方法添加到工具中。
//注意:由于 OnUpdate 方法会被频繁调用,应避免在此方法中执行耗时操作,
//因为这可能会降低应用程序用户界面的响应速度。
internal class SnippetButton : ArcGIS.Desktop.Framework.Contracts.Button
{
protected override void OnUpdate()
{
bool enableSate = true; //TODO: 编写启用状态的代码
bool criteria = true;  //TODO: 评估 disabledText 的条件
if (enableSate)
{
this.Enabled = true;  //工具启用
}
else
{
this.Enabled = false;  //工具禁用
//在此处自定义 disabledText
if (criteria)
this.DisabledTooltip = "缺少条件 1";
}
}
}

1.28 从当前程序集获取图像资源

public static void ExampleUsage()
{
// 图片 'Dino32.png' 作为资源添加,设置为“不复制”
var img = ForImage("Dino32.png");
// 使用图片...
}
public static BitmapImage ForImage(string imageName)
{
return new BitmapImage(PackUriForResource(imageName));
}
public static Uri PackUriForResource(string resourceName, string folderName = "Images")
{
// 获取当前程序集的名称(不带扩展名)
string asm = System.IO.Path.GetFileNameWithoutExtension(
System.Reflection.Assembly.GetExecutingAssembly().Location);
// 构建资源路径的URI字符串
string uriString = folderName.Length > 0
? string.Format("pack://application:,,,/{0};component/{1}/{2}", asm, folderName, resourceName)
: string.Format("pack://application:,,,/{0};component/{1}", asm, resourceName);
// 返回绝对URI
return new Uri(uriString, UriKind.Absolute);
}

1.29 阻止ArcGIS Pro关闭

// 有两种方法可以阻止ArcGIS Pro关闭
// 1. 在您的插件的模块中重写CanUnload方法并返回false。
// 2. 订阅ApplicationClosing事件并在接收到事件时取消它
internal class Module1 : Module
{
// 当ArcGIS Pro关闭时由Framework调用
protected override bool CanUnload()
{
// 返回false以取消应用程序关闭
return false;
}
internal class Module2 : Module
{
public Module2()
{
ArcGIS.Desktop.Framework.Events.ApplicationClosingEvent.Subscribe(OnApplicationClosing);
}
~Module2()
{
ArcGIS.Desktop.Framework.Events.ApplicationClosingEvent.Unsubscribe(OnApplicationClosing);
}
private Task OnApplicationClosing(System.ComponentModel.CancelEventArgs args)
{
args.Cancel = true;
return Task.FromResult(0);
}
// cref: ARCGIS.DESKTOP.CORE.EVENTS.PROJECTOPENEDEVENT
// cref: ARCGIS.DESKTOP.CORE.EVENTS.PROJECTOPENEDEVENT.SUBSCRIBE
// cref: ARCGIS.DESKTOP.CORE.EVENTS.PROJECTOPENEDEVENT.UNSUBSCRIBE
// cref: ARCGIS.DESKTOP.FRAMEWORK.CONTRACTS.MODULE.INITIALIZE
// cref: ARCGIS.DESKTOP.FRAMEWORK.CONTRACTS.MODULE.UNINITIALIZE
#region 如何确定项目何时打开
protected override bool Initialize() // 当模块初始化时调用
{
ProjectOpenedEvent.Subscribe(OnProjectOpened); // 订阅项目打开事件
return base.Initialize();
}
private void OnProjectOpened(ProjectEventArgs obj) // 项目打开事件处理程序
{
MessageBox.Show($"{Project.Current} has opened"); // 显示消息框
}
protected override void Uninitialize() // 取消订阅项目打开事件
{
ProjectOpenedEvent.Unsubscribe(OnProjectOpened); // 取消订阅
return;
}

1.30 如何在MapView中定位可嵌入控件

public ProSnippetMapTool()
{
// 在构造函数中,将MapTool基类的OverlayControlID设置为可嵌入控件的DAML ID
this.OverlayControlID = "ProAppModule1_EmbeddableControl1";
}
protected override void OnToolMouseDown(MapViewMouseButtonEventArgs e)
{
if (e.ChangedButton == System.Windows.Input.MouseButton.Left)
e.Handled = true;
}
protected override Task HandleMouseDownAsync(MapViewMouseButtonEventArgs e)
{
return QueuedTask.Run(() =>
{
// 将点击的屏幕坐标点赋值给MapTool基类的OverlayControlPositionRatio属性
this.OverlayControlPositionRatio = e.ClientPoint;
});
}

1.31 在激活选项卡时,CommandSearch 中建议的命令选项

//在模块类中..
public override string[] GetSuggestedCMDIDs(string activeTabID)
{
//返回你希望作为(建议的)默认值的静态 daml id 列表,这些默认值与给定的选项卡相关。
//它可以是与 activeTabID 关联的命令中的无、部分或全部。
//在此示例中,有两个选项卡。此示例任意地
//为每个选项卡标识一个命令,作为在命令搜索列表中显示的默认值(当_该_特定选项卡处于活动状态时)
switch (activeTabID)
{
case "CommandSearch_Example_Tab1":
return new string[] { "CommandSearch_Example_Button2" };
case "CommandSearch_Example_Tab2":
return new string[] { "CommandSearch_Example_Button4" };
}
return new string[] { "" };
}

1.32 从命令行启动 ArcGIS Pro

C:\>"C:\Program Files\ArcGIS Pro\bin\ArcGISPro.exe"  # 运行ArcGIS Pro的可执行文件

1.33 获取命令行参数

如果你的插件需要使用自定义的命令行参数,你的参数必须采用 “/argument” 的形式——请注意正斜杠 “/”。参数中不能包含空格。如果命令行中包含要打开的项目(参见从命令行打开项目),则自定义参数或开关必须放在项目文件名参数之前。

string[] args = System.Environment.GetCommandLineArgs(); // 获取命令行参数数组
foreach (var arg in args)
{
// 查找你的命令行开关
}

1.34 应用程序加速器(快捷键)

可以在您的 Add-in config.daml 中使用 accelerators/insertAccelerator DAML 元素来添加快捷键,其中 refID 是您要关联加速器(即快捷键)的元素的引用 ID。

<accelerators>
<!-- 为打开项目按钮添加快捷键 Ctrl+O -->
<insertAccelerator refID="esri_core_openProjectButton" flags="Ctrl" key="O" />
<!-- 为重做按钮添加快捷键 Ctrl+Y -->
<insertAccelerator refID="esri_core_redoButton" flags="Ctrl" key="Y" />
<!-- 为撤销按钮添加快捷键 Ctrl+Z -->
<insertAccelerator refID="esri_core_undoButton" flags="Ctrl" key="Z" />
</accelerators>

注意:可以在 updateModule 元素中使用 deleteAcceleratorupdateAccelerator DAML 元素来分别删除或修改应用程序加速器。
flags 可以是以下之一:Shift、Ctrl、Alt、Ctrl+Shift、Alt+Shift、Ctrl+Alt、Ctrl+Alt+Shift。

1.35 使用 Pro 样式在 DAML 中定义控件

有许多 ArcGIS Pro 样式可以应用于窗格和停靠窗格上的按钮、标签和其他控件,以使您的插件与 ArcGIS Pro 无缝融合。下面列出了一些最常见的样式。更多样式和颜色请参阅社区示例库中的 Styling-With-ArcGIS-Pro 示例。

按钮样式

<Button Content="Button" Style="{StaticResource Esri_SimpleButton}" ToolTip="Button"> <!-- 简单按钮样式 -->
<Button Content="Button" Style="{StaticResource Esri_BackButton}" ToolTip="Button"> <!-- 返回按钮样式 -->
<Button Content="Button" Style="{StaticResource Esri_BackButtonSmall}" ToolTip="Button"> <!-- 小返回按钮样式 -->
<Button Content="Button" Style="{StaticResource Esri_CloseButton}" ToolTip="Button"> <!-- 关闭按钮样式 -->

停靠窗格标题样式

<TextBlock Text="MyDockPane" Style="{StaticResource DockPaneHeading}" <!-- 停靠窗格标题样式 -->
VerticalAlignment="Center" HorizontalAlignment="Center"/>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Winemonk

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值