框架

如何在停靠窗格可见或隐藏时订阅和取消订阅事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private SubscriptionToken _eventToken = null;
// Called when the visibility of the DockPane changes.
protected override void OnShow(bool isVisible)
{
if (isVisible && _eventToken == null) //Subscribe to event when dockpane is visible
{
_eventToken = MapSelectionChangedEvent.Subscribe(OnMapSelectionChangedEvent);
}

if (!isVisible && _eventToken != null) //Unsubscribe as the dockpane closes.
{
MapSelectionChangedEvent.Unsubscribe(_eventToken);
_eventToken = null;
}
}
//Event handler when the MapSelection event is triggered.
private void OnMapSelectionChangedEvent(MapSelectionChangedEventArgs obj)
{
MessageBox.Show("Selection has changed");
}

执行命令

1
2
3
4
5
IPlugInWrapper wrapper = FrameworkApplication.GetPlugInWrapper("esri_editing_ShowAttributes");
var command = wrapper as ICommand; // tool and command(Button) supports this

if ((command != null) && command.CanExecute(null))
command.Execute(null);

设置当前工具

1
2
3
4
5
6
7
// use SetCurrentToolAsync
FrameworkApplication.SetCurrentToolAsync("esri_mapping_selectByRectangleTool");

// or use ICommand.Execute
ICommand cmd = FrameworkApplication.GetPlugInWrapper("esri_mapping_selectByRectangleTool") as ICommand;
if ((cmd != null) && cmd.CanExecute(null))
cmd.Execute(null);

激活选项卡

1
FrameworkApplication.ActivateTab("esri_mapping_insertTab");

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

1
2
3
4
5
// Define the condition in the DAML file based on the state 
if (activate)
FrameworkApplication.State.Activate("someState");
else
FrameworkApplication.State.Deactivate("someState");

确定应用程序是否繁忙

1
2
3
4
5
6
7
// The application is considered busy if a task is currently running on the main worker thread or any 
// pane or dock pane reports that it is busy or intiializing.

// Many Pro styles (such as Esri_SimpleButton) ensure that a button is disabled when FrameworkApplication.IsBusy is true
// You would use this property to bind to the IsEnabled property of a control (such as a listbox) on a dockpane or pane in order
// to disable it from user interaction while the application is busy.
bool isbusy = FrameworkApplication.IsBusy;

获取应用程序主窗口

1
2
3
4
5
6
System.Windows.Window window = FrameworkApplication.Current.MainWindow;

// center it
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;

关闭 ArcGIS Pro

1
FrameworkApplication.Close();

获取 ArcGIS 专业版

1
2
3
//"GetEntryAssembly" should be ArcGISPro.exe 
string version = System.Reflection.Assembly.GetEntryAssembly()
.GetName().Version.ToString();

关闭特定窗格

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
string _viewPaneID = "my pane"; //DAML ID of your pane
//You could have multiple instances (InstanceIDs) of your pane.
//So you can iterate through the Panes to get "your" panes only
IList<uint> myPaneInstanceIDs = new List<uint>();
foreach (Pane pane in FrameworkApplication.Panes)
{
if (pane.ContentID == _viewPaneID)
{
myPaneInstanceIDs.Add(pane.InstanceID); //InstanceID of your pane, could be multiple, so build the collection
}
}
foreach (var instanceID in myPaneInstanceIDs) //close each of "your" panes.
{
FrameworkApplication.Panes.ClosePane(instanceID);
}

激活窗格

1
2
3
4
5
6
7
8
9
var mapPanes = ProApp.Panes.OfType<IMapPane>();
foreach (Pane pane in mapPanes)
{
if (pane.Caption == "MyMap")
{
pane.Activate();
break;
}
}

获取有关当前安装的加载项的信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var addin_infos = FrameworkApplication.GetAddInInfos();
StringBuilder sb = new StringBuilder();

foreach (var info in addin_infos)
{
if (info == null)
break;//no addins probed

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}");
sb.AppendLine("");
}
System.Diagnostics.Debug.WriteLine(sb.ToString());
MessageBox.Show(sb.ToString(), "Addin Infos");

查找码头窗格

1
2
// in order to find a dockpane you need to know it's DAML id
var pane = FrameworkApplication.DockPaneManager.Find("esri_core_ProjectDockPane");

码头窗格属性和方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// in order to find a dockpane you need to know it's DAML id
var pane = FrameworkApplication.DockPaneManager.Find("esri_core_ProjectDockPane");

// determine visibility
bool visible = pane.IsVisible;

// activate it
pane.Activate();

// determine dockpane state
DockPaneState state = pane.DockState;

// pin it
pane.Pin();

// hide it
pane.Hide();

码头窗格撤消/重做

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// in order to find a dockpane you need to know it's DAML id
var pane = FrameworkApplication.DockPaneManager.Find("esri_core_contentsDockPane");

// get the undo stack
OperationManager manager = pane.OperationManager;
if (manager != null)
{
// undo an operation
if (manager.CanUndo)
await manager.UndoAsync();

// redo an operation
if (manager.CanRedo)
await manager.RedoAsync();

// clear the undo and redo stack of operations of a particular category
manager.ClearUndoCategory("Some category");
manager.ClearRedoCategory("Some category");
}

查找停靠窗格并获取其视图模型

1
2
3
4
5
6
7
8
9
10
11
12
// in order to find a dockpane you need to know it's DAML id.  

// Here is a DAML example with a dockpane defined. Once you have found the dockpane you can cast it
// to the dockpane viewModel which is defined by the className attribute.
//
//<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
2
//Opens the Backstage to the "About ArcGIS Pro" tab.
FrameworkApplication.OpenBackstage("esri_core_aboutTab");

访问当前主题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//Gets the application's theme
var theme = FrameworkApplication.ApplicationTheme;
//ApplicationTheme enumeration
if (FrameworkApplication.ApplicationTheme == ApplicationTheme.Dark)
{
//Dark theme
}

if (FrameworkApplication.ApplicationTheme == ApplicationTheme.HighContrast)
{
//High Contrast
}
if (FrameworkApplication.ApplicationTheme == ApplicationTheme.Default)
{
//Light/Default theme
}

显示专业消息框

1
ArcGIS.Desktop.Framework.Dialogs.MessageBox.Show("Some Message", "Some title", MessageBoxButton.YesNo, MessageBoxImage.Information, MessageBoxResult.Yes);

添加吐司通知

1
2
3
4
5
6
Notification notification = new Notification();
notification.Title = FrameworkApplication.Title;
notification.Message = "Notification 1";
notification.ImageUrl = @"pack://application:,,,/ArcGIS.Desktop.Resources;component/Images/ToastLicensing32.png";

ArcGIS.Desktop.Framework.FrameworkApplication.AddNotification(notification);

更改按钮标题或图像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
private void ChangeCaptionImage()
{
IPlugInWrapper wrapper = FrameworkApplication.GetPlugInWrapper("MyAddin_MyCustomButton");
if (wrapper != null)
{
wrapper.Caption = "new caption";

// ensure that T-Rex16 and T-Rex32 are included in your add-in under the images folder and have
// BuildAction = Resource and 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));
}

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);
}

获取按钮的工具提示标题

1
2
3
//Pass in the daml id of your button. Or pass in any Pro button ID.
IPlugInWrapper wrapper = FrameworkApplication.GetPlugInWrapper("button_id_from daml");
var buttonTooltipHeading = wrapper.TooltipHeading;

订阅活动工具更改事件

1
2
3
4
5
6
7
8
9
10
11
12
13
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)
{
string prevTool = args.PreviousID;
string newTool = args.CurrentID;
}

进度器 - 简单且不可取消

1
2
3
4
5
6
7
8
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;
//If you run this in the DEBUGGER you will NOT see the dialog
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() => Task.Delay(numSecondsDelay * 1000).Wait(), ps.Progressor);
}

进度器 - 可取消

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public async Task Progressor_Cancelable()
{
ArcGIS.Desktop.Framework.Threading.Tasks.CancelableProgressorSource cps =
new ArcGIS.Desktop.Framework.Threading.Tasks.CancelableProgressorSource("Doing my thing - cancelable", "Canceled");

int numSecondsDelay = 5;
//If you run this in the DEBUGGER you will NOT see the dialog

//simulate doing some work which can be canceled
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
cps.Progressor.Max = (uint)numSecondsDelay;
//check every second
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));
}
//are we done?
if (cps.Progressor.Value == cps.Progressor.Max) break;
//block the CIM for a second
Task.Delay(1000).Wait();

}
System.Diagnostics.Debug.WriteLine(string.Format("RunCancelableProgress: Canceled {0}",
cps.Progressor.CancellationToken.IsCancellationRequested));

}, cps.Progressor);
}

自定义按钮或工具的 disabedText 属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//Set the tool's loadOnClick attribute to "false" in the config.daml. 
//This will allow the tool to be created when Pro launches, so that the disabledText property can display customized text at startup.
//Remove the "condition" attribute from the tool. Use the OnUpdate method(below) to set the enable\disable state of the tool.
//Add the OnUpdate method to the tool.
//Note: since OnUpdate is called very frequently, you should avoid lengthy operations in this method
//as this would reduce the responsiveness of the application user interface.
internal class SnippetButton : ArcGIS.Desktop.Framework.Contracts.Button
{
protected override void OnUpdate()
{
bool enableSate = true; //TODO: Code your enabled state
bool criteria = true; //TODO: Evaluate criteria for disabledText

if (enableSate)
{
this.Enabled = true; //tool is enabled
}
else
{
this.Enabled = false; //tool is disabled
//customize your disabledText here
if (criteria)
this.DisabledTooltip = "Missing criteria 1";
}
}
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static void ExampleUsage()
{
//Image 'Dino32.png' is added as Build Action: Resource, 'Do not copy'
var img = ForImage("Dino32.png");
//Use the image...
}

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);
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);
return new Uri(uriString, UriKind.Absolute);
}

阻止 ArcGIS Pro 关闭

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// There are two ways to prevent ArcGIS Pro from closing
// 1. Override the CanUnload method on your add-in's module and return false.
// 2. Subscribe to the ApplicationClosing event and cancel the event when you receive it

internal class Module1 : Module
{

// Called by Framework when ArcGIS Pro is closing
protected override bool CanUnload()
{
//return false to ~cancel~ Application close
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 How to determine when a project is opened
protected override bool Initialize() //Called when the Module is initialized.
{
ProjectOpenedEvent.Subscribe(OnProjectOpened); //subscribe to Project opened event
return base.Initialize();
}

private void OnProjectOpened(ProjectEventArgs obj) //Project Opened event handler
{
MessageBox.Show($"{Project.Current} has opened"); //show your message box
}

protected override void Uninitialize() //unsubscribe to the project opened event
{
ProjectOpenedEvent.Unsubscribe(OnProjectOpened); //unsubscribe
return;
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public ProSnippetMapTool()
{
//Set the MapTool base class' OverlayControlID to the DAML id of your embeddable control in the constructor
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(() =>
{
//assign the screen coordinate clicked point to the MapTool base class' OverlayControlLocation property.
this.OverlayControlPositionRatio = e.ClientPoint;

});
}

激活选项卡时命令搜索中建议的命令选项。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//In the module class..
public override string[] GetSuggestedCMDIDs(string activeTabID)
{
//Return the static list of daml ids you want to be the (suggested)
//defaults relevant to the given tab. It can be none, some, or all of the
//commands associated with the activeTabID.
//In this example, there are two tabs. This example arbitrarily
//identifies just one command on each tab to be a default to show in the
//command search list (when _that_ particular tab is active)
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[] { "" };
}

从命令行启动 ArcGIS Pro

1
C:\>"C:\Program Files\ArcGIS Pro\bin\ArcGISPro.exe"

获取命令行参数

如果您的外接程序需要使用自定义命令行参数,则参数的格式必须为“/argument” - 请注意正斜杠“/”。不能有空格。如果命令行包含要打开的项目(请参阅从命令行打开项目),则必须将自定义参数或开关放在项目文件名参数之前。

1
2
3
4
5
string[] args = System.Environment.GetCommandLineArgs();
foreach (var arg in args)
{
// look for your command line switches
}

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

可以使用加速器/插入加速器 DAML 元素将应用程序加速器添加到外接程序 config.daml 中,该元素具有要与加速器关联的元素的 refID(即快捷方式)。

1
2
3
4
5
<accelerators>
<insertAccelerator refID="esri_core_openProjectButton" flags="Ctrl" key="O" />
<insertAccelerator refID="esri_core_redoButton" flags="Ctrl" key="Y" />
<insertAccelerator refID="esri_core_undoButton" flags="Ctrl" key="Z" />
</accelerators>

注意:使用 updateModule 元素中的 deleteAccelerator 和 updateAccelerator DAML 元素分别删除或更改应用程序加速器。 标志可以是以下之一:Shift、Ctrl、Alt、Ctrl+Shift、Alt+Shift、Ctrl+Alt、Ctrl+Alt+Shift

使用专业样式在 DAML 中定义控件

定义了许多 ArcGIS Pro 样式,这些样式可应用于窗格和停靠窗格上的按钮、标注和其他控件,以使加载项的外观与 ArcGIS Pro 无缝衔接。下面列出了一些最常见的样式。有关更多样式和颜色,请参阅社区示例存储库中的使用 ArcGIS Pro 设置样式示例。

按钮样式

1
2
3
4
<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">

码头窗格标题样式

1
2
<TextBlock Text="MyDockPane" Style="{StaticResource DockPaneHeading}" 
VerticalAlignment="Center" HorizontalAlignment="Center"/>