ProSnippets Framework
Language: C#
Subject: Framework
Contributor: ArcGIS Pro SDK Team <arcgisprosdk@esri.com>
Organization: Esri, http://www.esri.com
Date: 4/30/2026
ArcGIS Pro: 3.7
Visual Studio: 2026
Commands
Execute a command
IPlugInWrapper wrapper = FrameworkApplication.GetPlugInWrapper("esri_editing_ShowAttributes");
// tool and command(Button) supports this
if (wrapper is ICommand command && command.CanExecute(null))
command.Execute(null);
ArcGIS Pro status
Determine if the system is in airplane mode
bool isInAirplaneMode = ArcGIS.Core.SystemCore.Connectivity.IsInAirplaneMode();
Determine if the system is a mobile device e.g. a laptop or tablet vs a desktop
bool isMobileDevice = ArcGIS.Core.SystemCore.Connectivity.IsMobileDevice();
Determine the system's internet connection status
var connectionStatus = ArcGIS.Core.SystemCore.Connectivity.GetInternetConnectionStatus();
switch (connectionStatus)
{
case ArcGIS.Core.SystemCore.Connectivity.ConnectionStatus.statusPublic:
// The system has an active public connection.
break;
case ArcGIS.Core.SystemCore.Connectivity.ConnectionStatus.statusPrivate:
// The system does have an active private connection.
break;
case ArcGIS.Core.SystemCore.Connectivity.ConnectionStatus.statusDisconnected:
// The system's internet connection status is disconnected.
break;
}
Determine if the application is busy
// 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 initializing.
// 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;
Get the Application main window
Window window = Application.Current.MainWindow;
// center it
Rect rect = SystemParameters.WorkArea;
Application.Current.MainWindow.Left = rect.Left + (rect.Width - Application.Current.MainWindow.ActualWidth) / 2;
Application.Current.MainWindow.Top = rect.Top + (rect.Height - Application.Current.MainWindow.ActualHeight) / 2;
Set the current tool
// use SetCurrentToolAsync with await
FrameworkApplication.SetCurrentToolAsync("esri_mapping_selectByRectangleTool").Wait();
// or use ICommand.Execute
if (FrameworkApplication.GetPlugInWrapper("esri_mapping_selectByRectangleTool") is ICommand cmd && cmd.CanExecute(null))
cmd.Execute(null);
Activate a tab
FrameworkApplication.ActivateTab("esri_mapping_insertTab");
Activate/Deactivate a state - to modify a condition
// Define the condition in the DAML file based on the state
if (activate)
FrameworkApplication.State.Activate("someState");
else
FrameworkApplication.State.Deactivate("someState");
Close ArcGIS Pro
FrameworkApplication.Close();
Get ArcGIS Pro version
string version = System.Reflection.Assembly.GetEntryAssembly()
.GetName().Version.ToString();
ProWindow Position on Screen
double left = 250; //Window's left edge, in relation to the desktop
double top = 150; //Window's top edge, in relation to the desktop
var myProwindow = new ProWindow();
myProwindow.WindowStartupLocation = System.Windows.WindowStartupLocation.Manual;
myProwindow.Left = left;
myProwindow.Top = top;
//MetroWindows remember their last location unless SaveWindowPosition is set to
//false.
myProwindow.SaveWindowPosition = false;
myProwindow.Owner = FrameworkApplication.Current.MainWindow;
myProwindow.Closed += (o, e) => { myProwindow = null; };
myProwindow.Show();
//uncomment for modal
//myProwindow.ShowDialog();
Get an Image Resource from the Current Assembly
//Image 'Dino32.png' is added as Build Action: Resource, 'Do not copy'
var img = ForImage("Dino32.png");
//Use the image...
static BitmapImage ForImage(string imageName)
{
return new BitmapImage(PackUriForResource(imageName));
}
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);
}
Prevent ArcGIS Pro from Closing
// 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
// 1. Override the CanUnload method on your add-in's module and return false.
// Called by Framework when ArcGIS Pro is closing
{
//return false to ~cancel~ Application close
}
{
// 2. Subscribe to the ApplicationClosing event and cancel the event when you receive it
// Replace this line:
// ArcGIS.Desktop.Framework.Events.ApplicationClosingEvent.Subscribe(() => { });
// With the following, which matches the required delegate signature:
ArcGIS.Desktop.Framework.Events.ApplicationClosingEvent.Subscribe((args) =>
{
//Do something here, e.g. prompt user to save work
return Task.CompletedTask;
}
);
// in the Application Closing event handler set the Cancel property of the event args to true to prevent Pro from closing
}
}
// Called by Framework when ArcGIS Pro is closing
{
ArcGIS.Desktop.Framework.Events.ApplicationClosingEvent.Subscribe((args) =>
{
//Do something here, e.g. prompt user to save work
return Task.CompletedTask;
}
);
How to determine when a project is opened
// override the Initialize and Uninitialize methods of your add-in's module to subscribe and unsubscribe to the ProjectOpenedEvent
ProjectOpenedEvent.Subscribe(OnProjectOpened); //subscribe to Project opened event
ProjectOpenedEvent.Unsubscribe(OnProjectOpened); //unsubscribe from the event as the module is unloaded
void OnProjectOpened(ProjectEventArgs obj) //Project Opened event handler
{
MessageBox.Show($"{Project.Current} has opened"); //show your message box
}
Suggested command options in CommandSearch when a tab is activated.
//In the module class..
//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":
result = ["CommandSearch_Example_Button2"];
break;
case "CommandSearch_Example_Tab2":
result = ["CommandSearch_Example_Button4"];
break;
}
result = [""]; // Default case
ArcGIS Pro panes and dockpanes
Close a specific pane
List<uint> myPaneInstanceIDs = [];
foreach (Pane p in FrameworkApplication.Panes)
{
if (p.ContentID == paneID)
{
myPaneInstanceIDs.Add(p.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);
}
Activate a pane
var mapPanes = FrameworkApplication.Panes.OfType<IMapPane>();
foreach (Pane p in mapPanes.Cast<Pane>())
{
if (p.Caption == paneID)
{
p.Activate();
break;
}
}
Find a dockpane
// in order to find a dockpane you need to know its DAML id
var pane = FrameworkApplication.DockPaneManager.Find(dockPaneID);
Dockpane operations
// in order to find a dockpane you need to know its DAML id
pane = FrameworkApplication.DockPaneManager.Find(dockPaneID);
// 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();
Dockpane undo / redo
// in order to find a dockpane you need to know its DAML id
pane = FrameworkApplication.DockPaneManager.Find(dockPaneID);
// get the undo stack
OperationManager manager = pane.OperationManager;
if (manager != null)
{
// undo an operation
// Use await with UndoAsync and RedoAsync
if (manager.CanUndo)
manager.UndoAsync().Wait();
// redo an operation
if (manager.CanRedo)
manager.RedoAsync().Wait();
// clear the undo and redo stack of operations of a particular category
manager.ClearUndoCategory("Some category");
manager.ClearRedoCategory("Some category");
}
Find a dockpane and obtain its ViewModel
// 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>
DockpaneViewModel vm = FrameworkApplication.DockPaneManager.Find(dockPaneID) as DockpaneViewModel;
How to subscribe and unsubscribe to events when the dockpane is visible or hidden
// Override the OnShow method of a dockpane to subscribe and unsubscribe to events
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;
}
void OnMapSelectionChangedEvent(MapSelectionChangedEventArgs obj)
{
MessageBox.Show("Selection has changed");
}
ArcGIS Pro addins
Get Information on the Currently Installed Add-ins
var addin_infos = FrameworkApplication.GetAddInInfos();
StringBuilder sb = new();
foreach (var info in addin_infos)
{
if (info == null)
break;//no add-ins 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");
ArcGIS Pro backstage
Open the Backstage tab
//Opens the Backstage to the "About ArcGIS Pro" tab.
FrameworkApplication.OpenBackstage("esri_core_aboutTab");
ArcGIS Pro theme
Access the current theme
//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
}
ArcGIS Pro messages and notifications
Display a Pro MessageBox
ArcGIS.Desktop.Framework.Dialogs.MessageBox.Show("Some Message", "Some title", MessageBoxButton.YesNo, MessageBoxImage.Information, MessageBoxResult.Yes);
Add a toast notification
Notification notification = new()
{
Title = FrameworkApplication.Title,
Message = "Notification 1",
ImageSource = Application.Current.Resources["ToastLicensing32"] as ImageSource
};
FrameworkApplication.AddNotification(notification);
ArcGIS Pro tooltips and tools
Change a buttons caption or image
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;
wrapper.LargeImage = buildImage2;
}
Customize the disabledText property of a button or tool
//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.
{
bool enableState = true; //TODO: Code your enabled state
bool criteria = true; //TODO: Evaluate criteria for disabledText
if (enableState)
{
Enabled = true; //tool is enabled
}
else
{
Enabled = false; //tool is disabled
//customize your disabledText here
if (criteria)
DisabledTooltip = "Missing criteria 1";
}
}
Get a button's tooltip heading
//Pass in the id of your button. Or pass in any Pro button ID.
IPlugInWrapper wrapper = FrameworkApplication.GetPlugInWrapper(proButtonID);
var buttonTooltipHeading = wrapper.TooltipHeading;
Subscribe to Active Tool Changed Event
ArcGIS.Desktop.Framework.Events.ActiveToolChangedEvent.Subscribe((args) =>
{
string prevTool = args.PreviousID;
string newTool = args.CurrentID;
});
Unsubscribe to Active Tool Changed Event
ArcGIS.Desktop.Framework.Events.ActiveToolChangedEvent.Unsubscribe((args) =>
{
string prevTool = args.PreviousID;
string newTool = args.CurrentID;
});
ArcGIS Pro progress indicators
Progressor - Simple and non-cancelable
ProgressorSource ps = new("Doing my thing...", false);
int numSecondsDelay = 5;
//If you run this in the DEBUGGER you will NOT see the dialog
QueuedTask.Run(() => Task.Delay(numSecondsDelay * 1000).Wait(), ps.Progressor);
Cancelable Progressor
CancelableProgressorSource cps =
new("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
// Use await with QueuedTask.Run
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);
How to position an embeddable control inside a MapView
public ProSnippetMapTool()
{
//Set the MapTool base class' OverlayControlID to the DAML id of your embeddable control in the constructor
OverlayControlID = "ProAppModule1_EmbeddableControl1";
}
// Override the MapTool base class' OverlayControlPositionRatio property to set the position of the embeddable control
protected static void OnToolMouseDown(MapViewMouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
e.Handled = true;
}
// Override the MapTool base class' HandleMouseDownAsync method to set the position of the embeddable control
protected static Task HandleMouseDownAsync(MapViewMouseButtonEventArgs e)
{
return QueuedTask.Run(() =>
{
Point
//assign the screen coordinate clicked point to the MapTool base class' OverlayControlLocation property.
OverlayControlPositionRatio = e.ClientPoint;
});
}
Miscellaneous
Start ArcGIS Pro from the command line
C:\>"C:\Program Files\ArcGIS Pro\bin\ArcGISPro.exe"
Get Command Line Arguments
If your Add-in requires the use of custom command line arguments your arguments must be of the form "/argument" - note the forward slash "/". There must be no white space. If the command line contains a project to be opened (see Open project from command line) then custom arguments or switches must be placed before the project filename argument.
string[] args = System.Environment.GetCommandLineArgs();
foreach (var arg in args)
{
// look for your command line switches
}
Application Accelerators (Shortcut Keys)
Application accelerators can be added to your Add-in config.daml using an accelerators/insertAccelerator DAML element with the refID of the element to which you are associating the accelerator (i.e. short cut).
<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>
Note: Use the deleteAccelerator and updateAccelerator DAML elements within an updateModule element to remove or alter application accelerators respectively. Flags can be one of: Shift, Ctrl, Alt, Ctrl+Shift, Alt+Shift, Ctrl+Alt, Ctrl+Alt+Shift
Defining controls in DAML with Pro Styles
There are many ArcGIS Pro styles defined which can be applied to buttons, labels and other controls on your panes and dockpanes to make your add-ins look and feel seamless with ArcGIS Pro. Some of the most common styles are listed below. For more styles and colors see the Styling-With-ArcGIS-Pro sample in the Community Samples repo.
Button styles
<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">
Dockpane heading style
<TextBlock Text="MyDockPane" Style="{StaticResource DockPaneHeading}"
VerticalAlignment="Center" HorizontalAlignment="Center"/>