Esri provides multiple options for extending the functionality to ArcGIS Pro. Add-Ins are one of the 4 extensibility points using the ArcGIS Pro SDK for .NET and allow developers to create custom functionality, which appears in Pro’s ribbon and can be uniquely packaged in your choice of UI components (e.g., Pro Window, Dockpane, Button Palette, Button, etc.).
This post is a beginner’s guide to the process of creating a simple map exploration Add-In. We developed a free-and-open-source Zoom To Coordinates Add-In, which expands upon the default Esri functionality by providing the user options to create and customize graphics for their points of interest. This Add-In can be downloaded from the Esri Marketplace and the code in its entirety can be inspected in this GitHub repository. This post is not a step-by-step process for how this was achieved but rather covers some highlights along with covering some common pitfalls particular to using the SDK. We use modern .NET programming techniques such as WPF Binding, Task Asynchronous Programming (TAP), and the Model-View-View Model (MVVM) design pattern. This Add-In is compatible with ArcGIS Pro v3.x since it uses the latest version of the SDK available from Visual Studio 2022, which targets .NET 6.
Create a new Add-In project using the Add-In project template in Visual Studio and study the relationship between Config.daml and Module.cs. Config.daml is Esri’s XML standard, providing markup for defining where your various UI components will appear in the ArcGIS Pro ribbon, while Module.cs defines the entry point for your Add-In and is the subsystem where all your UI components reside. This is better appreciated once you create a UI element, such as a button, and can see how the button is declared within the module parent.
Now we’ll look at our actual Add-In with renamed filenames to underscore the subtleties of XAML naming conventions, which can be a common source of bugs.
Task Asynchronous Programming (TAP)
The Pro SDK leverages asynchronous programming to keep the Pro UI responsive and prevent it from freezing up when you have a long-running process. As an Add-In developer, you are mainly concerned with just two threads: the Graphical User Interface (GUI) thread and the Main CIM Thread (i.e., MCT). The Pro application state is maintained by the Cartographic Information Model (CIM) and uses the special worker thread called the MCT. Any methods referred to as “fine-grained” by the SDK team that impact the application state must be called on the MCT using the QueuedTask class or else a CalledOnWrongThreadException is thrown. Fortunately, the Pro SDK team makes this relatively simple to carry out since it leverages TAP whereby you use the async modifier to denote an asynchronous method and use await to denote the suspension point prior to calling QueuedTask.Run(). Methods that don’t require the MCT, yet still are asynchronous, and referred to as “coarse-grain” methods by the SDK team, have Async in their signature, and are safe to be called from the GUI thread (e.g., await MapView.Active.ZoomToSelectedAsync(new Timespan(0,0,3); ). Lastly, the SDK also provides developers with a third background thread that can be accessed using the BackgroundTask class and its Run() method - BackgroundTask.Run(); however, it’s less commonly used and is beyond the scope of this article.
WPF Binding and MVVM
Windows Presentation Foundation (WPF) and the Model-View-View Model (MVVM) design pattern are large and complex topics apart from the ArcGIS Pro SDK for .NET. Yet, to make robust Add-Ins while adhering to .NET best practices, we need to leverage concepts like WPF data binding and MVVM to decouple the UI (View) from the business logic (ViewModel), along with defining any necessary data classes (Model).
We use data binding to bind our ViewModel properties to the View and SetProperty() in our ViewModel, so that any changes occurring in the View automatically trigger a property change event, so our properties are updated in the ViewModel. Although we could use NotifyPropertyChange from the INotifyPropertyChange interface directly – as a non-Esri WPF app does – the Pro SDK team provides us with their own implementation, SetProperty(), resulting in fewer lines of code.
WPF commands provide a means for defining an action one time in the ViewModel and allowing it to be called in one or many places in the View via binding. The SDK provides us with an implementation of ICommand called RelayCommand that allows us to accomplish this.
Lastly, it’s important that you define the DataContext so that the View knows where the bound properties and commands reside. For this Add-In, which is comprised of two Views (i.e., ArcGIS Pro Windows) and a separate ViewModel for each, the DataContext gets defined in each of the View’s “code-behind” .cs files after the call to InitializeComponent().
We trust that this discussion has shed some light on ArcGIS Pro Add-Ins and has sparked ideas about the custom functionalities that could be integrated into Pro to address your specific business requirements. Reach out to dymaptic today to explore how we can assist you with software and GIS solutions tailored to your needs!