Skip to content

ProSnippets Framework

UmaHarano edited this page Nov 12, 2025 · 25 revisions
Language:              C#  
Subject:               Framework  
Contributor:           ArcGIS Pro SDK Team <[email protected]>  
Organization:          Esri, http://www.esri.com  
Date:                  11/7/2025  
ArcGIS Pro:            3.6  
Visual Studio:         2022  

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

ArcGIS Pro status

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;

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;

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"/>

Clone this wiki locally