Runtime Extensibility Framework
For Runtime .NET 100.12
Updated: 2021-10-02
The Runtime Extensibility Framework is a simple, open-source component
that enables development of extensible, configurable, MVVM applications
using the ArcGIS Runtime .NET SDK. Emphasis is placed on the following
concepts:
- A configuration is a single unique keyword that points to an XML
configuration file.
- The configuration file declares a view assembly containing the main
window UI, and one or more extensions.
- Each extension declaration points to an assembly that contains view
extensions, view model extensions, and other code. In addition, each
declaration can point to a view assembly. An application may refer to
multiple view assemblies, or may have only one view assembly containing
all UI items.
- View extensions are of the form Behavior<MapView>, and form
the basis of interaction between the application's MapView and any view
models. [There is no support for multiple MapViews at this time.]
- Different configurations may mix-and-match views, view extensions,
and view model extensions. Thus, one application may support a variety
of functionality and appearance based on various configurations.
RTReader, available for download, provides not only a ready-to-use
application, but also an example of configuring and supporting the
Extensibility Framework. This documentation will draw primarily upon it
for examples.
Supporting the Extensibility Framework
In order to support the Extensibility Framework, a class in the
application (typically the MainWindow model class) must implement the
IMainWindow interface:
- string ApplicationName { get; }: An arbitrary name, not
necessarily that of the executable.
- ImageSource WindowIcon { get; }: A default icon to use in
child windows
- string RuntimeVersion { get; }: The ArcGIS Runtime version
number (e.g. 100.12); AppUpdateAddin uses this value
- string UpdateLocation { get; }: An optional update location
to check for updates; AppUpdateAddin uses this value
- string Configuration { get; }: The keyword used to load the
configuration file. It is up to the application to determine how this
is set when it launches
- void SetTitle(string sTitle): Sets the title of the main
window (from the configuration file)
- void SetLayout(UserControl ucLayout): Sets the UI of the
main window (from the configuration file)
- event EventHandler AppClosing: Notifies that the application
is closing and should be cleaned up
When the application launches, the main window initializes the
Extensibility Framework by initializing the MapApplication object as
follows:
MapApplication.Init(pMainWindow);
where pMainWindow is an instance of a class that implements IMainWindow.
If the argument is null, MapApplication checks the application main
window to see if it implements IMainWindow.
The MapApplication class also exposes the following members:
- static MapApplication Current { get; }: The current
instance
- MainLayoutModel MainLayoutModel { get; }: The master data
context
- string ApplicationName { get; }: From IMainWindow
- string RuntimeVersion { get; }: From IMainWindow
- string UpdateLocation { get; }: From IMainWindow
- ImageSource WindowIcon { get; }: From IMainWindow
- event EventHandler AppReady;: Notifies that configuration
is fully processed
- void Status(string sMsg): From IStatus (see interfaces
below)
- void Status(string sMsg, bool bBusy): From IStatus
- void Message(string sMsg): From IStatus
- void Error(string sErr): From IStatus
- bool? CreateChildWindow(string sViewKey, string sViewName,
object ViewModel): spawns a child window or pane
- void Exit(): Closes the application
The MainLayoutModel is the master data context for the UI of the main
window. It exposes the following members for binding:
- IDictionary<string, object> DataContexts { get; }:
Contains data contexts for various controls, provided by extensions
- MapView MapViewContainerContent { get; }: The MapView for
the application (typically bound to a ContentPresenter)
- ObservableCollection<ChildItem> ChildItems { get; }:
When configured to do so, contains nonmodal child dialog panes (see
below)
- bool ChildItemsVisible { get; set; }: Determines whether
the collection of child items is visible
The following method is also exposed:
- void CheckChildItemsVisibility(): Hides the child item
collection if all items are hidden
The AppViewExt class is the default view extension; it provides an entry
point to the map and manages tool registration and activation. It
exposes the following members:
- static AppViewExt Current { get; }: The current instance
- Map Map { get; }: The current map
- bool Initialized { get; }: Whether the instance is fully
initialized
- BackgroundGrid MapBackground { get; set; }: Allows access
to MapView background
- MapViewInteractionOptions InteractionOptions { get; set; }:
Allows access to MapView interaction options
- event EventHandler MapChanged: Notifies
that map is replaced
- event EventHandler MapBackgroundChanged:
Notifies that MapView background is replaced
- async void SetMap(Map MyMap): Loads Map
- void SetMapCursor(Cursor MyCursor): Sets the MapView cursor
- ToolConfiguration GetDefaultConfiguration(): Gets a default
tool configuration
- void RegisterTool(IMapTool pTool): Registers a tool to be
managed by AppViewExt
- void SetTool(string sID = null): Sets the current tool, or
deactivates any active tool if null
- void Complete(): Completes the active tool geometry, if any
Three subfolders are expected to exist under the application executable,
or else to be created and populated from corresponding subfolders under
the folder defined by the UpdateLocation property:
- Config - contains one or more XML configuration files.
- Views - contains one or more view assemblies (.dll).
- Extensions - contains one or more extension assemblies (.dll).
Note that view and extension assemblies must have unique names. A view
assembly cannot have the same name as an extension assembly.
The main layout in a view library is a UserControl which is declared in
the configuration file (see below). Controls in the layout bind their
data contexts to the DataContexts[KEY] property, where the key is a
model extension provided by an extension class library. Here is an
example of a typical tool button:
<RadioButton
DataContext="{Binding DataContexts[QueryAddin.QueryTools]}"
Command="{Binding IdentifyCommand}"
ToolTip="Identify"
Style="{StaticResource LayoutToolStyle}"
IsChecked="{Binding IdentifyToolChecked}">
<Image
Source="Images/Identify.png"
Style="{StaticResource LayoutIconStyle}"/>
</RadioButton>
Also, a ContentPresenter control binds its Content property to the
MapViewContainerContent property, which is an instance of the MapView
control. Multiple MapViews are currently not supported.
<ContentPresenter
Grid.Column="1"
Content="{Binding MapViewContainerContent}" />
The following is a list of interfaces to be implemented by the
developer:
- IMainWindow: Implemented by the main window class of the
application
- IStatus: May be implemented by a model extension;
otherwise, MapApplication will use a default implementation
- IConfigurable: Optionally implemented by a model or view
extension
- IWindowContent: Implemented by the view model for a
nonmodal dialog window or pane
- IDialogContent: Implemented by the view model for a modal
dialog window
- IMapTool: Implemented by tools that are managed by
AppViewExt
Various helper classes also exist for the benefit of the developer:
- ConfigHelper: Access to configuration and assemblies
- DialogHelper: Common Windows dialog functions
- ResourceHelper: Access to view resources
- SettingsHelper: Manages settings
- CommandHelper: ICommand support
- ToolHelper: IMapTool support
The Configuration File
The configuration file is named after the Configuration property (plus
an .xml extension). [See the configuration file for RTReader for an
example.] There are two main sections in the configuration file:
"MainLayout" and "Extensions".
The "MainLayout" section contains the application title, the name of
view assembly containing the main UI, and the name of the main UI class
in the view assembly. [All UIs defining the main application and any
child windows are expected to be subclasses of UserControl.] In
addition, nonmodal child dialogs may be defined as instances of the
ChildWindow or ChildItem class. ChildItems are typically panes in a
multipane control such as a TabControl.
Here is an example MainLayout configuration:
<MainLayout>
<Title>DemoApp (TabletReader)</Title>
<ViewAssembly>TabletViews</ViewAssembly>
<MainLayoutName>MainLayout</MainLayoutName>
<NonModalChild>ChildItem</NonModalChild>
<ShowChildItemIcon>True</ShowChildItemIcon>
<ShowChildItemTitle>False</ShowChildItemTitle>
</MainLayout>
The "Extensions" section contains the declaration and configuration for
each extension to be used in the application. Each "Extension" entry
can have the following (optional) sections:
- "ViewAssembly": Registers the view assembly containing all of the
UI items referenced by the extension. Multiple extensions may refer to
the same view assembly.
- "ModelExtensions": Declares the view model extensions that will be
added to the master view model.
- "ViewExtensions": Declares any MapView behaviors and their bindings
to model extensions.
Model extensions and view extensions may optionally implement the
IConfigurable interface. In that case, a "ConfigData" section in
the XML configuration provides a string which may be parsed
appropriately by the extension upon loading.
Core Extensions
In addition to the main Extensibility component, code is also provided
for several core extensions. Binaries are only provided for those
extensions that are used in RTReader (NavAddin, QueryAddin, and
LayoutAddin). It is up to the developer to compile the other
extensions.
NavAddin
Provides support for map navigation, mobile map packages, ArcGIS map
services, table of contents, map copy/export, and GPS location
display.
The following commands are exposed to the UI:
Data Context Key | Command |
NavAddin.NavCommands | OpenMapCommand |
NavAddin.NavCommands | ExportMapCommand |
NavAddin.NavCommands | CopyMapCommand |
NavAddin.NavCommands | UserSettingsCommand |
NavAddin.NavCommands | ZoomInFixedCommand |
NavAddin.NavCommands | ZoomOutFixedCommand |
NavAddin.NavCommands | ZoomFullCommand |
NavAddin.NavCommands | ZoomPrevCommand |
NavAddin.NavCommands | ZoomNextCommand |
NavAddin.NavCommands | GPSCommand |
NavAddin.NavCommands | ShowTOCCommand |
NavAddin.NavCommands | HideTOCCommand |
NavAddin.NavCommands | ToggleCoordinatesCommand |
NavAddin.NavCommands | SetUnitsCommand |
NavAddin.NavCommands | ExitCommand |
NavAddin.NavModelExt | ScaleEnteredCommand |
NavAddin.NavTools | ZoomInCommand |
NavAddin.NavTools | ZoomOutCommand |
NavAddin.NavTools | PanCommand |
The following bindable properties are also exposed:
Data Context Key | Property | Type |
NavAddin.MapModelExt | TOC | ObservableCollection<TocDataItem> |
NavAddin.MapModelExt | StatusText | string |
NavAddin.MapModelExt | CoordinateVisibility | Visibility |
NavAddin.MapModelExt | CoordinateText | string |
NavAddin.MapModelExt | ProgressVisibility | Visibility |
NavAddin.NavCommands | OpenMapVisibility | Visibility |
NavAddin.NavCommands | GPSVisibility | Visibility |
NavAddin.NavModelExt | MapReady | bool |
NavAddin.NavModelExt | ScaleItemsSource | ObservableCollection<string> |
NavAddin.NavModelExt | ScaleSelectedIndex | int |
NavAddin.NavModelExt | ScaleVisibility | Visibility |
NavAddin.NavModelExt | IsScaleVisible | bool |
NavAddin.NavModelExt | ScaleText | string |
NavAddin.NavTools | ZoomInToolChecked | bool |
NavAddin.NavTools | ZoomInToolChecked | bool |
NavAddin.NavTools | PanToolChecked | bool |
The following views are expected to exist in the referenced view
library:
- GPSDialog
- UserSettingsDialog
The "ConfigData" section for the MapModelExt model extension can have
the following (optional) entries:
- "Map": Automatically loads a map, which can be one of three types.
"SimpleTestMap" loads a map containing the Esri World_Street_Map layer.
"WebMap" loads a web map given a Url. "BasicMap" is a map that can
contain one or more layer types: tile cache, mobile map package, ArcGIS
map image layer, or ArcGIS feature service layer; group layers are
honored in a mobile map package or map image layer. If an API key is
required for a web map or layer, it must be set by the application
(individual API keys are not yet supported).
- "EnableTOC": If "True" enables TOC support, and if "False"
(default) does not enable TOC support.
- "ChildWindowTOC": If "False" (default) assumes an existing bound
control for the TOC, and if "True" uses a nonmodal child dialog.
- "ShowTOC": Can be "False" (default) or "True" to automatically show
the TOC.
Here are some example entries:
<Map Type="SimpleTestMap" />
<Map Type="WebMap" Url="https://www.arcgis.com/home/item.html?id=388d367794ee43669606c04ca93eb8db" />
<Map Type="BasicMap" Background="#FFF0F0F0" MaxScale="10" Extent="-9816800, 5125500, -9809200, 5130500">
<TileCacheLayer DisplayName="Splash Screen" Path="C:\apps\DemoApp\Packages\SplashScreen.tpkx" MaxScale="30000" />
<TileCacheLayer DisplayName="Naperville Imagery" Path="C:\apps\DemoApp\Data\naperville_imagery.tpkx" IsVisible="False" />
<MobileMapPackageLayer DisplayName="Naperville Water" Path="C:\apps\DemoApp\Data\OfflineMapbook_v11.mmpk" MapIndex="1" IsExpanded="False" />
</Map>
<EnableTOC>True</EnableTOC>
<ChildWindowTOC>True</ChildWindowTOC>
<ShowTOC>False</ShowTOC>
QueryAddin
Provides support for Identify, Find, Go to XY, Measure, Highlight/Erase,
and Text tools.
The following commands are exposed to the UI:
Data Context Key | Command |
QueryAddin.QueryCommands | FindCommand |
QueryAddin.QueryCommands | GoToXYCommand |
QueryAddin.QueryTools | IdentifyCommand |
QueryAddin.QueryTools | MeasureCommand |
QueryAddin.QueryTools | HighlighterCommand |
QueryAddin.QueryTools | HighlighterMenuCommand |
QueryAddin.QueryTools | EraserCommand |
QueryAddin.QueryTools | EraserMenuCommand |
QueryAddin.QueryTools | TextCommand |
The following bindable properties are also exposed:
Data Context Key | Property | Type |
QueryAddin.QueryTools | IdentifyToolChecked | bool |
QueryAddin.QueryTools | MeasureToolChecked | bool |
QueryAddin.QueryTools | HighlighterIcon | Image |
QueryAddin.QueryTools | HighlighterToolChecked | bool |
QueryAddin.QueryTools | HighlighterText | String |
QueryAddin.QueryTools | EraserIcon | Image |
QueryAddin.QueryTools | EraserToolChecked | bool |
QueryAddin.QueryTools | EraserText | String |
QueryAddin.QueryTools | TextToolChecked | bool |
The following views are expected to exist in the referenced view
library:
- AttachmentDialog
- FindDialog
- GoToXYDialog
- IdentifyDialog
- MeasureDialog
- TextDialog
The "ConfigData" section for the QueryModelExt model extension can have
the following (optional) entries:
- "Identify": Used to declare "ResultCollection" and "QueryRelated"
options. "ResultCollection" specifies the aggregation of identify
result items, and can be "List" or "Tree" (default). "QueryRelated"
specifies whether related records should be retrieved for identify
results, and can be "False" or "True" (default). If "ResultCollection"
is "List", then "QueryRelayed" is ignored (assumed "False").
- "QueryLayerHelper" specifies an assembly and class name that should
be used instead of the BasicQueryLayerHelper class. The class must
implement the IQueryLayerHelper interface.
- "AttachmentDialogModel" specifies an assembly and class name that
should be used instead of the BasicAttachmentDialogModel class. The
class must implement the IAttachmentDialogModel interface.
Here are some example entries:
<Identify ResultCollection="Tree" QueryRelated="True" />
<AttachmentDialogModel Assembly="EditAddin" ClassName="EditAttachmentDialogModel" />
LayoutAddin
Provides support for map layouts that can be printed or exported to PDF.
[PDF export assumes that the "Microsoft Print to PDF" driver is
available.]
The following command is exposed to the UI:
Data Context Key | Command |
LayoutAddin.LayoutModelExt | OpenLayoutCommand |
The following bindable property is also exposed:
Data Context Key | Property | Type |
LayoutAddin.LayoutModelExt | OpenLayoutVisibility | Visibility |
The following views are expected to exist in the referenced view
library:
The "ConfigData" section for the LayoutModelExt model extension can have
a "Layouts" entry containing one or more "Layout" entries. Each
"Layout" entry must specify values for "Name", "DisplayName",
"PageWidth", and "PageHeight" (using 96 dpi). A Layout may have
optional "Property" entries to populate text blocks:
- "Input": a string to be entered by the user. Optional parameters:
"Label".
- "Scale": the current scale of the map. Optional parameters:
"PageUnit", "DistanceUnit".
- "Date": the current date. Optional parameters: "FormatString".
Here is an example XAML mark-up for a layout:
<UserControl x:Class="LayoutTest.AdHocLetterPortrait"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="1056" d:DesignWidth="816">
<UserControl.Resources>
<TextBlock x:Key="Title" Text="Ad Hoc Letter Portrait" />
<Size x:Key="PageSize" Height="1056" Width="816" />
</UserControl.Resources>
<Canvas Height="1056" Width="816" Background="White">
<Border Canvas.Left="48" Canvas.Bottom="48" Width="720" Height="960" BorderBrush="Black" BorderThickness="3">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="48" />
</Grid.RowDefinitions>
<Border Grid.Row="0" Margin="12, 12, 12, 0" BorderBrush="Blue" BorderThickness="3">
<ContentPresenter Content="{Binding MapViewContainerContent}" />
</Border>
<Canvas Grid.Row="1">
<TextBlock Canvas.Bottom="12" Canvas.Left="12" FontSize="24" Text="{Binding LayoutProperties[Title], FallbackValue=Title}" />
<TextBlock Canvas.Top="6" Canvas.Left="440" FontSize="10" Text="Scale:" />
<TextBlock Canvas.Top="6" Canvas.Left="480" FontSize="10" Text="{Binding LayoutProperties[Scale], FallbackValue=N/A}" />
<TextBlock Canvas.Top="24" Canvas.Left="440" FontSize="10" Text="Date:" />
<TextBlock Canvas.Top="24" Canvas.Left="480" FontSize="10" Text="{Binding LayoutProperties[Date], FallbackValue=N/A}" />
</Canvas>
</Grid>
</Border>
</Canvas>
</UserControl>
And here is an example configuration for it:
<Layout Name="AdHocLetterPortrait" DisplayName="Ad Hoc Letter Portrait" PageWidth="816" PageHeight="1056">
<Properties>
<Property Name="Title" Type="Input" Label="Map Title" />
<Property Name="Scale" Type="Scale" PageUnit="Inch" DistanceUnit="Feet"/>
<Property Name="Date" Type="Date" FormatString="MM-dd-yyyy" />
</Properties>
</Layout>
EditAddin
Provides support for online editing or offline editing via the Sync
Framework [Runtime Basic licensing may be required].
The following commands are exposed to the UI:
Data Context Key | Command |
EditAddin.EditModelExt | DeleteGDBCommand |
EditAddin.EditModelExt | SynchronizeCommand |
The following bindable property is also exposed:
Data Context Key | Property | Type |
EditAddin.EditModelExt | SynchronizeVisibility | Visibility |
The following views are expected to exist in the referenced view
library:
- AttachmentDialog
- AuthenticationDialog
- CaptureDialog
- SynchronizeDialog
In order to work with QueryAddin, the "AttachmentDialogModel" entry
should be set as follows:
<AttachmentDialogModel Assembly="EditAddin" ClassName="EditAttachmentDialogModel" />
The "ConfigData" section for the EditModelExt model extension can have
the following optional entry:
- "SynchronizeVisible" (default "True"): Sets the value of
SynchronizeVisibility.
The "ConfigData" section for the EditViewExt view extension can have the
following entries:
- "RemoteFeatureService" [required]: Specifies the URL of a feature
service.
- "EditLayers" [required]: Specifies the layers to be edited.
- "LocalGeodatabase" [optional]: Specifies the path of the local
Runtime geodatabase to be created and/or synchronized. If not present,
only direct edits to the remote feature service are supported.
- "AOI" [optional]: The geographic extent to be downloaded and
synchronized (in DD). Required if LocalGeodatabase is specified.
- "PortalAuth" [optional]: specifies the URL for Portal or ArcGIS
Online authentication. If "AutoUserName" is "True", then the user's OS
sign-in ID is automatically used. [Tip: if the service is hosted by
ArcGIS Online, have the application assign an API Key instead.]
Here is an example configuration:
<RemoteFeatureService Url="https://services.arcgis.com/nnn/arcgis/rest/services/Naperville_Markup/FeatureServer" />
<LocalGeodatabase Path="C:\apps\DemoApp\Data\EditDemo.geodatabase" />
<EditLayers GroupLayerName="Markups" Visible="True">
<EditLayer Name="Map Change Request" Visible="True" ShowLabels="False" />
</EditLayers>
<AOI XMin="-88.17" YMin="41.77" XMax="-88.13" YMax="41.80" />
Here is an example of a Portal service:
<RemoteFeatureService Url="https://gis.myserver.com/arcgis/rest/services/TestService/FeatureServer" />
<PortalAuth Url="https://gis.myserver.com/portal/sharing/rest" AutoUserName="True"/>
It is up to the developer to create the code to perform the actual
edits, typically in an exension. A feature table may be accessed from
EditAddin as follows:
ArcGISFeatureTable fTab = EditModelExt.Current.GetFeatureTable(sTableName);
AppUpdateAddin
Provides support for application updates, Runtime updates, local file
updates, and local dataset updates. Multiple dataset/Runtime update
locations are supported. The extension makes the following
assumptions:
- Application files reside under
[IMainWindow.UpdateLocation]\[IMainWindow.ApplicationName]
- Extensibility.dll resides under
[IMainWindow.UpdateLocation]\Extensibility
- Extension DLLs reside under [IMainWindow.UpdateLocation]\Extensions
- View DLLs reside under [IMainWindow.UpdateLocation]\Views
- Runtime deployment packages are zipped and reside in the
"Deployments" folder adjacent to the dataset update folder
- Any new Runtime deployment will be placed into the current
ArcGISRuntimeEnvironment.InstallPath
- Datasets are always packaged in zip files
- If multiple dataset update locations exist, they are defined in the
file DataLocations.txt in the [IMainWindow.UpdateLocation]\Datasets
folder.
The following command is exposed to the UI:
Data Context Key | Command |
AppUpdateAddin.UpdateModelExt | SetLocationCommand |
The following bindable property is also exposed:
Data Context Key | Property | Type |
EditAddin.EditModelExt | LocationVisibility | Visibility |
The following view is expected to exist in the referenced view
library:
The extension should be the first in the "Extensions" section of the
config file. The "ConfigData" section for the UpdateModelExt model
extension is optional. The following entries may or may not be
present:
- "SetUpdateFolder": If "True", multiple dataset update locations
exist and a preferred location must be set by the user
- "Deletions:" Specify old files or folders to remove
- "FileUpdates": Defines local non-application files to check for
updates
- "DatasetUpdates": Defines local datasets to check for updates
Here is a sample configuration:
<SetUpdateFolder>True</SetUpdateFolder>
<Deletions>
<Delete Path="C:\apps\DemoApp\Temp" />
</Deletions>
<FileUpdates>
<File Source="Packages\SplashScreen.tpkx" Destination="C:\apps\DemoApp\Packages" />
</FileUpdates>
<DatasetUpdates>
<Dataset Name="naperville_imagery.tpkx" Destination="C:\apps\DemoApp\Data" />
<Dataset Name="OfflineMapbook_v11.mmpk" Destination="C:\apps\DemoApp\Data" />
</DatasetUpdates>
Configuration Examples
- Example 1: Offline
configuration with editing
- Example 2: Online configuration
with editing
Creating an Extension
More to come (hopefully)!
Return to ArcGIS Runtime page