Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
.NET
Table of Contents
Developer's guide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
What you can do . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Get started
Install the SDK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Install the toolkit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
Add ArcGIS Runtime SDK references . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Class diagrams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
Tutorials
Add a map to your app . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Use ArcGIS basemaps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
Access feature data in the cloud . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
Access maps and content from your portal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
Add geocoding to your app . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Get driving directions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
Create an offline app . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
Use the MVVM design pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
Fundamentals
Maps and layers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
Layer Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
Features and graphics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
Graphics rendering modes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
Symbols and renderers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
Spatial references . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
Work with local services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
Asynchronous programming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
Threading considerations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
Guidelines, best practices, tips, and tricks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
Build a map
Use a MapView to display a map . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
Navigate the map . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
Work with web maps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
Add layers with code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
Create an offline map . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
Multiple maps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
Display information
Add graphics and text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
Label map features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
Display map overlays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
Show device location . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
Display military messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
Work with 3D
Developer's guide
This guide describes how to use ArcGIS Runtime SDK for .NET to build Windows (Desktop, Store, or Phone) apps that incorporate
capabilities such as mapping, query, analysis, routing and navigation, and more. A great place to start developing once you've installed
the SDK is to add a map to your app or browse the wide variety of samples. For release notes and known issues with this release, see the
Release notes topic.
ArcGIS Runtime SDK for .NET enables developers to create applications for Windows Desktop, Windows Store app, and Windows Phone
platforms with high-quality interactive mapping, queries, geocoding, routing, data editing, and advanced geographic analysis.
The three APIs included with the SDK share a common design and implementation that enables the reuse of the application logic between
apps built for each platform. Functionally, the SDK combines the powerful, high performance mapping and analysis capabilities of the
ArcGIS Runtime with features of the ArcGIS platform that supports connected and disconnected workflows.
ArcGIS Runtime SDK for .NET allows your apps to provide functionality like the following:
Display an interactive map with rich cartography that contains data from a variety of sources
Add features, rasters, and basemaps stored locally on a device
Use a powerful set of tasks that leverage ArcGIS capabilities to analyze your maps and provide information to your users
Search, query, and identify geographic features using any combination of spatial, attribute, or temporal criteria
Calculate optimal routes between locations and generate directions
Enable users to collect and edit data in the field
Synchronize data collected in the field with your enterprise geodatabase
Reuse your app's logic across the Windows Desktop, Windows Store app, and Windows Phone platforms
Note: All three APIs install when running the default setup if the system requirements for each are met. If you don't
have the option to install one of the APIs, check your development machine to ensure it meets the system
requirements for that API.
Steps:
1. Double-click the setup file (downloaded previously) to start the setup.
2. Click Next in the welcome screen.
3. If you accept the license agreement, click the I accept the license agreement option and click Next.
4. In the Select Features panel, choose each API you want to install.
5. Click Change if you want to install to a location other than the default.
6. Click Next.
7. Finally, click Install in the last panel of the wizard to begin the installation.
The installation takes a few moments to copy and register the required files.
Once your ArcGIS Runtime SDK for .NET successfully installs, you are ready to start programming with the ArcGIS
Runtime SDK for .NET.
Next steps
You are ready to begin developing ArcGIS applications using the ArcGIS Runtime SDK for .NET. Here are a few ways you can get started:
Work through the Add a map to your app tutorial.
Explore code samples.
Explore SDK concepts and features.
Install the toolkit
Related Topics
Tutorial: Add a map to your app
Install the toolkit
System requirements
Note: The toolkit is not required for building ArcGIS Runtime apps. It contains additional controls and utilities that
facilitate implementing some functionality in your app. The ArcGIS Runtime SDK for .NET Toolkit GitHub
repository describes the features of the toolkit.
The easiest way to use the toolkit in your project is to install ArcGIS Runtime SDK for .NET Toolkit NuGet Package using the Visual Studio
NuGet Package Manager.
1. Right-click your project node in the Visual Studio Solution Explorer window
2. Choose Manage NuGet Packages from the context menu
If you want to download the source code for the toolkit and include it in your project, follow these steps to get the toolkit solution from
GitHub.
1. Clone the ArcGIS Runtime SDK for .NET Toolkit GitHub repository to your desktop or download the ZIP file.
2. Open the Esri.ArcGISRuntime.Toolkit.sln solution in Visual Studio.
3. Build the solution for the platform and configuration you need.
4. In the project for your app, add a reference to the toolkit by browsing to the output assembly created by the build.
See the README.md file for the arcgis-toolkit-dotnet repository for a description of toolkit features and additional information.
Tip: ArcGIS Runtime SDK for .NET provides a project template for creating your mapping app, called ArcGIS
Runtime 10.2.7 for .NET App. Creating your project from the template will add the appropriate references
and a page with a map view containing a single base layer. In this tutorial, you'll build your app from a blank
template.
Create a Windows Store app
You'll use Visual Studio to create a Windows Store app.
Steps:
1. Open a supported version of Microsoft Visual Studio.
2. Choose File > New > Project (or click New Project on the Start page) to create a project.
3. Click Store Apps > Windows Apps > Blank App (Windows) in the New Project dialog box (you can create your project in
either C# or VB .NET).
Note: Visual Studio 2015 organizes project types slightly differently. You'll find Store projects under
Windows 8 > Windows
Tip: If you decide to use the ArcGIS Runtime template, you will not need to complete the steps
described in this topic.
4. Choose a folder location for your new project and give it a name.
Steps:
1. Right-click the References node under your project listing in the Visual Studio Solution Explorer window, and click Add
Reference in the context menu.
2. Check the listing for the ArcGIS Runtime for Windows Store apps assembly under Windows 8.1 > Extensions.
Note: In order for your app to build, you need to specify a build target for the project. The default value of
Any CPU will not work and is why the new references are shown with a yellow warning icon.
You will now specify a build platform for the app.
4. Choose BUILD > Configuration Manager.
5. Choose x86 in the Active solution platform drop-down menu. This will target a 32-bit platform for the app.
Steps:
1. Open the MainPage.xaml file in the Visual Studio designer.
2. Go to the XAML view of the designer and add the following XML namespace reference to the Page XAML element. Visual
Studio offers Intellisense to help complete the URL portion of the statement.
xmlns:esri="using:Esri.ArcGISRuntime.Controls"
xmlns:layers="using:Esri.ArcGISRuntime.Layers"
The Esri.ArcGISRuntime.Controls namespace contains the MapView control and Map class that you will need if you
want to place a map on your page. Esri.ArcGISRuntime.Layers contains, as you might expect, a variety of Layer
classes that can be added to the Map. You can now use the prefixes for the references (esri and layers) to add objects
from these namespaces. Depending on the objects you need to work with in your XAML, you may need to make additional
namespace references. When making a reference, Visual Studio Intellisense helps you by displaying a list of available
namespaces, as shown below.
Tip: For readability, define your XML namespaces with prefixes that allow you to easily identify to
which namespace it refers. For example, use sym to refer to the
Esri.ArcGISRuntime.Symbology namespace. Being consistent in your naming also allows
you to move XAML between projects without having to make edits.
3. You can now use the XML prefixes you've defined to work with ArcGIS Runtime SDK objects in your XAML. The following
code sample defines a new MapView control and Map containing a single basemap layer.
<esri:MapView x:Name="MyMapView">
<esri:Map x:Name="MyMap">
<layers:ArcGISTiledMapServiceLayer ID="BaseMap"
ServiceUri="http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer"/>
</esri:Map>
</esri:MapView>
The process described in this topic is generally the first thing you'll do for each ArcGIS Runtime SDK for .NET project you create from a
standard Visual Studio template. The details for adding these references differ slightly between SDK platforms.
Related Topics
Tutorial: Add a map to your app
Class diagrams
The following object model diagrams (OMD) describe the classes available in the ArcGIS Runtime assemblies.
Overview
Esri.ArcGISRuntime.ArcGISServices
Esri.ArcGISRuntime.Controls
Esri.ArcGISRuntime.Data
Esri.ArcGISRuntime.Geometry
Esri.ArcGISRuntime.Http
Esri.ArcGISRuntime.Hydrographic
Esri.ArcGISRuntime.Layers
Esri.ArcGISRuntime.Location
Esri.ArcGISRuntime
Esri.ArcGISRuntime.Portal
Esri.ArcGISRuntime.Security
Esri.ArcGISRuntime.Symbology
Esri.ArcGISRuntime.Tasks (1/2)
Esri.ArcGISRuntime.Tasks (2/2)
Esri.ArcGISRuntime.WebMap
Prerequisites
This tutorial requires a supported version of Microsoft Visual Studio and ArcGIS Runtime SDK for .NET. Refer to the appropriate topics in
the guide for information on installing the SDK and system requirements.
Familiarity with Visual Studio and a basic understanding of XAML is recommended but not required.
Tip: ArcGIS Runtime SDK for .NET provides a project template for creating your mapping app, called
ArcGIS Runtime 10.2.7 for .NET App. Creating your project from the template will add the
appropriate references and a page with a map view containing a single base layer. In this tutorial,
you'll build your app from a blank template.
4. Choose a folder location for your new project and name it HelloWorldMap.
7. Check the listing for the ArcGIS Runtime for Windows Store apps assembly under Windows 8.1 > Extensions.
Note: In order for your app to build, you need to specify a build target for the project. The default value of
Any CPU will not work and is why the new references are shown with a yellow warning icon.
You will now specify a build platform for the app.
9. Choose BUILD > Configuration Manager.
10. Choose x86 in the Active solution platform drop-down menu. This will target a 32-bit platform for the app.
Hello, World!
Now that you've created a blank project and referenced ArcGIS Runtime SDK for .NET, you're ready to add a map to your app. ArcGIS
Runtime allows you to work with geographic data from a variety of sources, including those local to your app as well as data provided
remotely as an Internet service. In this tutorial, you'll display street data from a public map service provided by ArcGIS Online.
Steps:
To use the library in the XAML designer, you must first make a reference to the XML namespace for ArcGIS Runtime.
1. Double click the MainPage.xaml file in the Visual Studio Solution Explorer to open it in the designer.
2. Go to the XAML view of the designer, and add the following XML namespace reference to the Page XAML element. Visual
Studio offers IntelliSense to help complete the URL portion of the statement.
xmlns:esri="using:Esri.ArcGISRuntime.Controls"
xmlns:layers="using:Esri.ArcGISRuntime.Layers"
4. Add the following XAML inside the <Map> element to define a new layer to display in the map:
<layers:ArcGISTiledMapServiceLayer ID="BaseMap"
ServiceUri="http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer"/>
The ArcGISTiledMapServiceLayer represents a map layer based on a cached map service hosted by ArcGIS for
Server. The ID property provides a unique identifier for the layer that can be used to refer to the layer programmatically
(although you won't need to in this tutorial). ServiceUri defines the source for the layer. The layer in your map will come
from a tiled map service hosted on ArcGIS Online.
Tip: In addition to the World imagery map, ArcGIS Online provides basemaps of streets, topographic
data, historical maps, and many others. Visit Living Atlas of the World to browse some of the
available basemaps. If you find a basemap you'd like to use in your app, you can copy the service
URI from its description page.
5. Click the Start button on the Standard toolbar (or DEBUG > Start Debugging) to start your app. You'll see a map similar to
the following:
By default, the map displays at the full extent of the first (bottom) layer it contains. To show the initial view of the map at a
particular location, you can add logic to the map's XAML or programmatically adjust the extent when the app starts. To
practice setting the initial extent, proceed to the next section.
Hello, Cleveland!
As a finishing touch to your app, you will add a ViewpointExtent element to the map's XAML to define the extent at which the map
should initially be displayed.
Steps:
1. Add the following XAML inside your Map element. It can go either before or after the existing
ArcGISTiledMapServiceLayer element.
<esri:Map.InitialViewpoint>
<esri:ViewpointExtent XMin="-9113800"
YMin="5077300"
XMax="-9078300"
YMax="5091800"/>
</esri:Map.InitialViewpoint>
The previous XAML sets the map's InitialViewpoint property with an ViewpointExtent element that defines the
desired extent (centered on Cleveland, Ohio USA). The dimensions of the envelope are specified with Web Mercator
coordinate values to match the coordinate system of the map.
2. Run the app again. The map displays with an initial extent centered on Cleveland Ohio, as shown in the following screen
capture:
<Grid>
<esri:MapView x:Name="MyMapView">
<esri:Map x:Name="MyMap" >
<esri:Map.InitialViewpoint>
<esri:ViewpointExtent XMin="-9113800"
YMin="5077300"
XMax="-9078300"
YMax="5091800"/>
</esri:Map.InitialViewpoint>
<layers:ArcGISTiledMapServiceLayer ID="BaseMap"
ServiceUri="http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer"/>
</esri:Map>
</esri:MapView>
</Grid>
</Page>
That's it. You created a simple map app with only a few lines of XAML. As a next step, consider exploring the functionality provided by
ArcGIS Runtime SDK for .NET by stepping through more advanced tutorials or by examining the many samples provided with the SDK.
Related Topics
Work with web maps
Navigate the map
Use a MapView to display a map
Access feature data in the cloud
Use ArcGIS basemaps
Prerequisites
This tutorial requires a supported version of Microsoft Visual Studio and ArcGIS Runtime SDK for .NET. Refer to the appropriate topics in
the guide for information on installing the SDK and system requirements.
Familiarity with Visual Studio and a basic understanding of XAML and C# or VB.NET is recommended.
Tip: ArcGIS Runtime SDK for .NET provides a project template for creating your mapping app, called
ArcGIS Runtime 10.2.7 for .NET App. Creating your project from the template will add the
appropriate references and a page with a map view containing a single base layer. In this tutorial,
you'll build your app from a blank template.
4. Choose a folder location for your new project and name it Basemaps.
Note: In order for your app to build, you need to specify a build target for the project. The default value of
Any CPU will not work and is why the new references are shown with a yellow warning icon.
You will now specify a build platform for the app.
9. Choose BUILD > Configuration Manager.
10. Choose x86 in the Active solution platform drop-down menu. This will target a 32-bit platform for the app.
Steps:
To use the library in the XAML designer, you must first make a reference to the XML namespace for ArcGIS Runtime.
1. Open the MainPage.xaml file in the Visual Studio designer.
2. Go to the XAML view of the designer, and add the following XML namespace reference to the Page XAML element. Visual
Studio offers IntelliSense to help complete the URL portion of the statement.
xmlns:esri="using:Esri.ArcGISRuntime.Controls"
xmlns:layers="using:Esri.ArcGISRuntime.Layers"
Next, you'll add a MapView control to the window and define a layer to display.
3. Add the following XAML inside the <Grid> element to define a new MapView control on the page:
<esri:MapView x:Name="MyMapView">
<esri:Map x:Name="MyMap">
</esri:Map>
</esri:MapView>
4. Add the following XAML inside the <Map> element to define the basemap layer (World street map) to display in the map:
<layers:ArcGISTiledMapServiceLayer ID="BaseMap"
ServiceUri="http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer"/>
The ArcGISTiledMapServiceLayer represents a map layer based on a cached map service hosted by ArcGIS for
Server. The ID property provides a unique identifier for the layer that can be used to refer to the layer programmatically,
which is something you'll do later in the tutorial. ServiceUri defines the source for the layer. The layer in your map will
come from a tiled map service hosted on ArcGIS Online.
Tip: In addition to the World imagery map, ArcGIS Online provides basemaps of streets, topographic
data, historical maps, and many others. Visit Living Atlas of the World to browse some of the
available basemaps. If you find a basemap you'd like to use in your app, you can copy the service
URI from its description page.
5. Add the following XAML to define the hurricane layer (ArcGISDynamicMapServiceLayer). By adding this XAML below
the line that defines the basemap, you are ensuring that it will draw on top of the tiled basemap (world streets) layer.
<layers:ArcGISDynamicMapServiceLayer ID="Hurricanes"
ServiceUri="http://sampleserver6.arcgisonline.com/arcgis/rest/services/Hurricanes/MapServer"/>
The map displays a layer of hurricane activity over the World Street Map basemap from ArcGIS Online. When the app is
complete, your user will be able to change the basemap layer while the app is running.
Steps:
1. Drag a ComboBox control from the Visual Studio Toolbox onto the design surface for MainWindow.xaml. Make sure the
new ComboBox displays on top of the MapView control.
Tip: To change the draw order for a control, simply change its position in the XAML. Elements that
appear below the Map definition in the XAML document, for example, will appear on top of the
MapView control.
2. Edit the XAML for the new ComboBox to contain three new items, as shown in the following code sample. Each item defines
a basemap that the user can choose to display in the map.
<ComboBox HorizontalAlignment="Left" VerticalAlignment="Top"
Margin="10,10,0,0" Width="120">
<ComboBox.Items>
<ComboBoxItem Content="Streets" IsSelected="True"
Tag="http://services.arcgisonline.com/arcgis/rest/services/World_Street_Map/MapServer"/>
<ComboBoxItem Content="Topo"
Tag="http://services.arcgisonline.com/arcgis/rest/services/World_Topo_Map/MapServer"/>
<ComboBoxItem Content="Imagery"
Tag="http://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer"/>
</ComboBox.Items>
</ComboBox>
3. Define a new event handler forthe SelectionChanged event, as shown in the following code sample. As you type, Visual
Studio provides IntelliSense to create the event handler for you.
<ComboBox
HorizontalAlignment="Left" VerticalAlignment="Top"
Margin="10,10,0,0" Width="120"
SelectionChanged="ComboBox_SelectionChanged">
4. Right-click the name of the handler (ComboBox_SelectionChanged) in the designer, and choose Go To Definition from
the context menu.
5. Add the following code to the ComboBox_SelectionChanged event handler:
var combo = sender as ComboBox;
var sel = combo.SelectedItem as ComboBoxItem;
if (sel.Tag == null) { return; }
// Find and remove the current basemap layer from the map
if (MyMap == null) { return; }
var oldBasemap = MyMap.Layers["BaseMap"];
MyMap.Layers.Remove(oldBasemap);
// Create a new basemap layer
var newBasemap = new Esri.ArcGISRuntime.Layers.ArcGISTiledMapServiceLayer();
// Set the ServiceUri with the url defined for the ComboBoxItem's Tag
newBasemap.ServiceUri = sel.Tag.ToString();
// Give the layer the same ID so it can still be found with the code above
newBasemap.ID = "BaseMap";
// Insert the new basemap layer as the first (bottom) layer in the map
MyMap.Layers.Insert(0, newBasemap);
The current basemap layer is referenced in the code using the ID value that you assigned in the XAML (BaseMap). A new
layer is created, and the Tag property of the selected item is used to set the ServiceUri property. Your XAML defines a
Tag for each ComboBoxItem with a URL that points to a basemap service hosted on ArcGIS Online. The same ID is then
given to the new layer so the next time the code runs, the current basemap layer can again be found.
Finally, the new basemap is added to the map's layer collection using the Insert method. This method allows you to
specify where in the collection you want the new layer to appear. The Add method can also be used to add a new layer but
will always add the layer to the end of the collection (which will appear as the top layer in the map).
Steps:
1. Click the Start button on the Standard toolbar (or DEBUG > Start Debugging) to start your app.
2. Choose a different basemap layer from the UI (that is, something other than Streets).
The map updates to display the new basemap. Notice that the new basemap layer is added to the bottom of the layer
display, ensuring that the dynamic layer (hurricanes) is not obscured.
Tip: You can also use your own basemaps, hosted on ArcGIS Online or with ArcGIS for Server, in
your ArcGIS Runtime SDK for .NET apps.
Your app is now complete. By providing a unique ID for each layer in your map, you can reference them later when you need to make a
change. You may also find this technique useful when you need to change layer visibility, add a graphic to an existing graphics layer, alter
a feature layer's renderer, and so on.
As a next step, consider exploring the functionality provided by ArcGIS Runtime SDK for .NET by stepping through more tutorials or by
examining the many samples provided with the SDK.
Related Topics
Tutorial: Access maps and content from your portal
Access feature data in the cloud
Use a MapView to display a map
Navigate the map
Prerequisites
This tutorial requires a supported version of Microsoft Visual Studio and ArcGIS Runtime SDK for .NET. Refer to the appropriate topics in
the guide for information on installing the SDK and system requirements.
Familiarity with Visual Studio and a basic understanding of XAML and C# or VB .NET is recommended.
Tip: ArcGIS Runtime SDK for .NET provides a project template for creating your mapping app, called
ArcGIS Runtime 10.2.7 for .NET App. Creating your project from the template will add the
appropriate references and a page with a map view containing a single base layer. In this tutorial,
you'll build your app from a blank template.
4. Choose a folder location for your new project and name it AccessFeatureData.
Note: In order for your app to build, you need to specify a build target for the project. The default value of
Any CPU will not work and is why the new references are shown with a yellow warning icon.
You will now specify a build platform for the app.
9. Choose BUILD > Configuration Manager.
10. Choose x86 in the Active solution platform drop-down menu. This will target a 32-bit platform for the app.
Steps:
To use the library in the XAML designer, you must first make a reference to the XML namespace for ArcGIS Runtime.
1. Open the MainPage.xaml file in the Visual Studio designer.
2. Go to the XAML view of the designer, and add the following XML namespace reference to the Page XAML element. Visual
Studio offers IntelliSense to help complete the URL portion of the statement.
xmlns:esri="using:Esri.ArcGISRuntime.Controls"
xmlns:layers="using:Esri.ArcGISRuntime.Layers"
xmlns:data="using:Esri.ArcGISRuntime.Data"
xmlns:sym="using:Esri.ArcGISRuntime.Symbology"
Next, you'll add a MapView containing a Map control to the window and define a basemap layer.
3. Add the following XAML inside the <Grid> element to define a new MapView control on the page:
<esri:MapView x:Name="MyMapView">
<esri:Map x:Name="MyMap">
</esri:Map>
</esri:MapView>
4. Add the following XAML inside the Map element to define an ArcGIS Online basemap layer to display in the map:
<layers:ArcGISTiledMapServiceLayer ID="BaseMap"
ServiceUri="http://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer"/>
Basemaps provide the context and a framework for working with information geographically. A basemap is used for
locational reference and presents a framework on which to overlay your operational layers, perform tasks, and visualize
geographic information. In the following steps, you'll overlay a feature layer with the basemap.
Tip: In addition to the World imagery map, ArcGIS Online provides basemaps of streets, topographic
data, historical maps, and many others. Visit Living Atlas of the World to browse some of the
available basemaps. If you find a basemap you'd like to use in your app, you can copy the service
URI from its description page.
Steps:
1. Add the following XAML to define a FeatureLayer to display on top of the imagery basemap layer you defined earlier.
Note that layers appearing first inside the Map contents display below layers that are defined later. The following XAML,
therefore, is placed below the XAML that defines the basemap layer.
<layers:FeatureLayer ID="PoolPermits">
<layers:FeatureLayer.FeatureTable>
<data:ServiceFeatureTable
ServiceUri="http://sampleserver6.arcgisonline.com/arcgis/rest/services/PoolPermits/FeatureServer/0"/>
</layers:FeatureLayer.FeatureTable>
</layers:FeatureLayer>
The FeatureLayer represents a single layer from an ArcGIS feature service. The ID property provides a unique identifier
for the layer that can be used to refer to the layer programmatically. The FeatureTable defines the data source for the
layer by specifying a ServiceFeatureTable and its ServiceUri property. The layer above will display parcels in
Riverside, California. It has attributes to describe whether or not each parcel has a swimming pool and whether the proper
permit has been obtained.
Since the operational layer in your app is focused on a small area of the city of Riverside California, you'll define an initial
extent for the map that centers on the area of interest.
2. Add the following XAML inside your Map element:
<esri:Map.InitialViewpoint>
<esri:ViewpointExtent XMin="-13075816.40"
YMin="4014771.46"
XMax="-13073005.67"
YMax="4016869.78"/>
</esri:Map.InitialViewpoint>
The values for the initial map extent were obtained by consulting the REST page for the pool permits layer (available through
the ServiceUri property). This ensures that the map extent contains the full extent of the operational layer when the app is
initially started.
You are now ready to test your app.
3. Click the Start button on the Standard toolbar (or DEBUG > Start Debugging) to start your app. A map similar to the
following is displayed:
The map displays an imagery basemap overlaid with the swimming pool permits layer at the extent of the operational layer.
The features in red are lots that have a pool but have not been issued a permit for one. To simplify the map display, you'll
filter this layer to include only the parcels that are in violation and display them with a custom polygon symbol.
Steps:
1. Open a web browser and navigate to the URI for the pool permits layer: http://sampleserver6.arcgisonline.com/arcgis/rest/
services/PoolPermits/FeatureServer/0.
2. Scroll to the Fields section.
To filter the display of the features in your pool permits layer, you'll use values in the pool_permit and has_pool fields.
Notice that these fields are of integer type, and based on the coded value domain, a value of 0 means "No" and 1 means
"Yes".
3. Add the following XAML to the GeodatabaseFeatureTable element to define the Where property for the FeatureLayer:
<layers:FeatureLayer ID="PoolPermits">
<layers:FeatureLayer.FeatureTable>
<data:ServiceFeatureTable Where="has_pool = 1 AND pool_permit = 0"
ServiceUri="http://sampleserver6.arcgisonline.com/arcgis/rest/services/PoolPermits/FeatureServer/0"/>
</layers:FeatureLayer.FeatureTable>
</layers:FeatureLayer>
4. Run the app. Your map now displays only those features that meet the criteria you've specified: lots with a pool that do not
have a permit.
Steps:
1. Add the following XAML inside the FeatureLayer element to define a new SimpleRenderer for the layer. This defines a
simple renderer with a single fill symbol. The symbol will have a hashed aqua fill and a dotted red outline.
<layers:FeatureLayer.Renderer>
<sym:SimpleRenderer>
<sym:SimpleFillSymbol Color="Aqua" Style="DiagonalCross">
<sym:SimpleFillSymbol.Outline>
<sym:SimpleLineSymbol Color="Firebrick" Width="4" Style="Solid"/>
</sym:SimpleFillSymbol.Outline>
</sym:SimpleFillSymbol>
</sym:SimpleRenderer>
</layers:FeatureLayer.Renderer>
Steps:
1. Add the following XAML to define a UI for displaying parcel information (APN and address). This XAML should go below the
XAML that defines your MapView to ensure it displays on top of that control.
<StackPanel Orientation="Vertical" Background="Blue" Opacity=".8"
HorizontalAlignment="Left" VerticalAlignment="Top">
<StackPanel Orientation="Horizontal" Margin="5">
<TextBlock Text="Address:" FontWeight="Bold"/>
<TextBlock x:Name="AddressTextBlock" Text="--" Margin="5,0"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="5">
<TextBlock Text="APN:" FontWeight="Bold"/>
<TextBlock x:Name="ApnTextBlock" Text="--" Margin="5,0"/>
</StackPanel>
<Button x:Name="GetParcelAddressButton" Content="Get Parcel Info"/>
</StackPanel>
2. Add the following XAML to the GetParcelAddressButton button to define an event handler for the Click event. When
prompted by IntelliSense, create a new event handler. The event handler is given the default name of
GetParcelAddressButton_Click.
<Button x:Name="GetParcelAddressButton"
Content="Get Parcel Info"
Click="GetParcelAddressButton_Click"/>
3. In the XAML Editor, right-click the name of the event handler (GetParcelAddressButton_Click) and choose Go To
Definition in the context menu that appears.
Visual Studio takes you to the Code Editor view. Before working on the code for the button click handler, you need to add a
couple of using statements for required namespaces.
4. At the top of your MainPage.xaml.cs code module, add the following using statements:
using Esri.ArcGISRuntime.Layers;
using Esri.ArcGISRuntime.Tasks.Query;
While the MapView control exposes interaction events, such as MouseUp, MouseDown, TouchUp, and TouchDown, these
events aren't always the best places to capture geometry from the user. Such events on the control will fire when the user
zooms and pans on the map, which might require you to add logic to handle multiple types of map interaction.
Each MapView control has an associated Editor that is accessible from the Editor property. In addition to helping you
configure editing functionality, the Editor class provides methods for obtaining geometry from the user. You'll use the
RequestPointAsync method on the Editor to get a point for identifying a parcel on the map.
5. Return to the GetParcelAddressButton_Click event handler. Start your function with the following code to get the map
point for the location clicked by the user:
var mapPoint = await MyMapView.Editor.RequestPointAsync();
Using the await keyword, your query will complete asynchronously before the code below it is executed. The compiler
treats this code as a callback for the function called with await. To use the await keyword, however, you must mark the
function containing it with the async keyword.
Note: See the Asynchronous programming topic for more information about the .NET task-based
asynchronous pattern.
7. Return to the body of your function. Add the following code to set up a QueryTask object that will find a feature at the
location specified by the user:
var poolPermitUrl = "http://sampleserver6.arcgisonline.com/arcgis/rest/services/PoolPermits/FeatureServer/0";
var queryTask = new QueryTask(new System.Uri(poolPermitUrl));
var queryFilter = new Query(mapPoint);
queryFilter.OutFields.Add("apn");
queryFilter.OutFields.Add("address");
Notice that the QueryTask constructor takes an argument that specifies the URI for the service to query. The Query object
defines the spatial and/or attribute criteria (the where clause) for the query. The previous code uses the map point to do a
spatial search using the default spatial relationship, which is SpatialRelationship.Intersects. Since you need to
display the APN and address values for the feature, those fields must be added to the OutFields collection, as shown in
the previous code example.
8. Add the following code to execute the query. If a result is found, its APN and address values are displayed in the UI.
var queryResult = await queryTask.ExecuteAsync(queryFilter);
if (queryResult.FeatureSet.Features.Count > 0)
{
var resultGraphic = queryResult.FeatureSet.Features[0] as Graphic;
ApnTextBlock.Text = resultGraphic.Attributes["apn"].ToString();
AddressTextBlock.Text = resultGraphic.Attributes["address"].ToString();
}
9. Run your app. Zoom in to a part of the map displaying pool permit features. Click the Get Parcel Info button, then click one
of the features in the map to display its APN and address values. Click the button again, and try a neighboring parcel that is
not currently displayed in the map. You'll see information for these locations as well.
In this tutorial, you learned how to access, filter, and display data from an ArcGIS feature service. As you can see, feature layers give you
flexibility to modify the content and appearance of feature service data for use in your app. To learn more, take a look at the many
samples available that illustrate the use of feature layers.
Related Topics
Tutorial: Access maps and content from your portal
Work with web maps
Add layers with code
Search for features
Tip: With your free ArcGIS for Developers account, you have access to ArcGIS Online for development and
testing, including the ability to create hosted feature services.
Learn more about ArcGIS Online.
Portal for ArcGIS provides you with the same core capabilities as ArcGIS Online, but can be installed and hosted on-premises, behind the
firewall for controlled distribution of content. Portal for ArcGIS is the technology that powers ArcGIS Online and is available to implement in
your organization.
ArcGIS Online for organizations, on the other hand, lets your organization be a part of ArcGIS Online through a subscription, without
needing to install or manage any server technology. With this subscription, you can set up a configurable secured site that includes
administrative controls, flexible data storage capabilities, and other provisions that enable geospatial information to be more pervasive
within your organization or general public. Through the subscription, you can also access the Esri cloud to turn your data into web
accessible maps.
The ArcGIS Runtime SDK allows developers to access and search content, users, and groups of a general portal (on-premises instance
or ArcGIS Online) or a specific organization's subscription within that portal. Classes in the API wrap calls to the ArcGIS REST API to
communicate with the back end portal.
In this tutorial, you learn how to find and access content stored in a portal, and to incorporate that content into your app.
Prerequisites
This tutorial requires a supported version of Microsoft Visual Studio and ArcGIS Runtime SDK for .NET. Refer to the appropriate topics in
the guide for information on installing the SDK and system requirements.
Familiarity with Visual Studio, XAML, and C# is recommended.
Tip: ArcGIS Runtime SDK for .NET provides a project template for creating your mapping app, called
ArcGIS Runtime 10.2.7 for .NET App. Creating your project from the template will add the
appropriate references and a page with a map view containing a single base layer. In this tutorial,
you'll build your app from a blank template.
4. Choose a folder location for your new project and name it PortalApp.
Note: In order for your app to build, you need to specify a build target for the project. The default value of
Any CPU will not work and is why the new references are shown with a yellow warning icon.
You will now specify a build platform for the app.
9. Choose BUILD > Configuration Manager.
10. Choose x86 in the Active solution platform drop-down menu. This will target a 32-bit platform for the app.
Add a MapView
Your app will contain an empty MapView control. At runtime, your app will connect to, and display content from, ArcGIS Online.
Begin by creating a basic UI for your app. To use the classes in the ArcGIS Runtime API, define XML namespace references in
MainPage.xaml.
Steps:
1. Open the MainPage.xaml page in XAML view.
2. Add the following XAML in the Page element of MainPage.xaml to define an XML namespace reference for the ArcGIS
Runtime API controls.
xmlns:esri="using:Esri.ArcGISRuntime.Controls"
3. Inside the Grid element on the page, add the XAML below to create an empty MapView control. Assign the name
MyMapView to the control so you can reference it in your code behind.
<esri:MapView x:Name="MyMapView"/>
Your MapView displays maps and layers from a portal (ArcGIS Online) while the app runs.
Create a search UI
Your app allows the user to search a portal for web maps, feature services, and basemap layers. The user can get a description and
thumbnail for search results, and display an item on the map. Begin by creating a UI to receive search criteria from the user and display a
list of results.
When complete, your UI looks like the following:
Steps:
1. Open your MainPage.xaml page in XAML view. Add the following XAML inside the existing Grid element on the page,
immediately below the line that defines the MapView.
<StackPanel Width="300"
HorizontalAlignment="Right"
Margin="10">
<StackPanel Orientation="Horizontal"
Margin="5">
<TextBlock Text="Search:"/>
<TextBox x:Name="SearchTextBox"
Width="100"
Margin="10,0"
HorizontalContentAlignment="Right"
Text="Turtle"/>
<ComboBox x:Name="ItemTypeComboBox"
SelectedValuePath="Content"
Width="120">
<ComboBoxItem Content="Web map" IsSelected="True"/>
<ComboBoxItem Content="Feature service"/>
<ComboBoxItem Content="Basemap"/>
</ComboBox>
</StackPanel>
<Button x:Name="SearchButton"
Content="Search ArcGIS.com"
Margin="20"
HorizontalAlignment="Center"/>
<ListBox x:Name="ResultListBox"
Margin="20,0"
MaxHeight="200">
<!-- results shown here -->
</ListBox>
<TextBlock x:Name="SnippetTextBlock"
Text=""
Height="50"
Margin="10"
TextWrapping="Wrap"/>
<Image x:Name="ThumbnailImage"
Stretch="UniformToFill"
Width="200" Height="133"/>
<Button x:Name="ShowMapButton"
Content="Show Map"
Margin="5"
Width="150"
HorizontalAlignment="Center"
IsEnabled="False"/>
</StackPanel>
The ResultListBox shows portal items that match your user's search criteria. Add an ItemTemplate to the list box to
define how the result items display.
2. Add the following XAML inside the ListBox element, below the <!-- results shown here --> comment.
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Title}"/>
<TextBlock Text="{Binding Owner}" FontSize="9"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
The DataTemplate uses data binding to display the Title and Owner for each search result. At runtime, the ListBox
binds to a list of ArcGISPortalItem objects. Title and Owner are properties of those objects.
3. Define a click event handler for the search button as shown in the following example.
<Button x:Name="SearchButton"
Content="Search ArcGIS.com"
Margin="20"
Click="SearchButton_Click"/>
4. Right-click the SearchButton_Click handler in your XAML and choose Go To Definition in the context menu. You will
add code to this handler to search the portal.
Steps:
1. At the top of the MainPage.xaml.cs file, add the following using statements for ArcGIS Runtime API namespaces you
need.
using Esri.ArcGISRuntime.Controls;
using Esri.ArcGISRuntime.Portal;
using Esri.ArcGISRuntime.WebMap;
2. Inside the MainPage class, add the variable declarations below. These variables store private references to the portal
(ArcGIS Online) and to the currently selected search result (if any).
3. Add the async keyword to the definition of the SearchButton_Click function, as shown in bold in the following example.
private async void SearchButton_Click(object sender, RoutedEventArgs e)
The async keyword in the function definition indicates that asynchronous calls are made in the function that uses the await
keyword.
4. Add the following try catch block to the SearchButton_Click function. If an exception is encountered while searching,
the error message is shown to the user.
try
{
}
catch (Exception ex)
{
var msg = new Windows.UI.Popups.MessageDialog(ex.Message, "Error searching portal");
msg.ShowAsync();
}
5. Inside the try portion of the block, add the following code to initialize a connection to the portal, if it doesn't already exist.
// if first run, get a ref to the portal (ArcGIS Online)
if (this.arcGISOnline == null)
{
// create the uri for the portal
var portalUri = new Uri("https://www.arcgis.com/sharing/rest");
// create the portal
this.arcGISOnline = await ArcGISPortal.CreateAsync(portalUri);
}
The Esri.ArcGISRuntime.Portal.ArcGISPortal class provides static methods that allow you to connect to a portal.
Note: If you call the static ArcGISPortal.CreateAsync method without arguments, a connection is
made to ArcGIS Online. In the previous code, the portalUri variable can be omitted from the
arguments and it works the same. If you want to connect to another portal, you provide the portal
URI as shown.
6. After the if block that initializes the arcGISOnline variable, declare a variable to store results of a portal search. The
results are an enumerable of ArcGISPortalItem.
// create a variable to store search results (collection of portal items)
IEnumerable<ArcGISPortalItem> results = null;
7. Next, add the following branching statement based on the type of item the user wants to search.
if (this.ItemTypeComboBox.SelectedValue.ToString() == "Basemap")
{
}
else
{
A search for basemaps uses a different method (SearchBasemapGalleryAsync) and doesn't require a query expression.
8. In the if portion of your branching statement, add the following code for basemap searches. This asynchronously searches
the portal for basemaps and stores the results.
// basemap search returns web maps that contain the basemap layer
var basemapSearch = await this.arcGISOnline.ArcGISPortalInfo.SearchBasemapGalleryAsync();
results = basemapSearch.Results;
Note: SearchBasemapGalleryAsync returns a collection of web maps. Each web map in the results
contains the basemap layer described in the portal item.
9. Below the branching statement, add the following code to bind the collection of portal items to the results list box. You will
add the code for the else portion of the branching statement in a following step.
// show the results in the list box
this.ResultListBox.ItemsSource = results;
10. Run your app. Choose Basemap from the combo box and click the Search ArcGIS.com button. Several results appear in
the list.
Note: Your app does not use the query text when searching
basemaps.
11. Stop running your app and return to Visual Studio. Next, you will add code to find web map and feature service portal items
using a search term.
12. In the else portion of your branching statement, add the following code to build a query expression using information
provided by the user.
// get the search term and item type provided in the UI
var searchTerm = this.SearchTextBox.Text.Trim();
var searchItem = this.ItemTypeComboBox.SelectedValue.ToString();
// build a query that searches for the specified type
// ('web mapping application' is excluded from the search since 'web map' will match those item types too)
var queryString = string.Format("\"{0}\" type:(\"{1}\" NOT \"web mapping application\")", searchTerm, searchItem);
Note: The query string uses the search term provided by the user and also narrows the search to a
specified item type. Because a search for items of type Web map also matches items of type Web
mapping application, those items have been explicitly excluded from the search using the
NOT portion of the expression.
13. A search for portal items requires a SearchParameters object. Add the following code (directly below the code you added
previously) to create a new SearchParameters object that defines the query expression, search result sorting preferences,
and maximum number of results for the search.
A maximum of 10 portal items return for the search, sorted highest to lowest according to the average user rating.
14. Add the following code to execute the search using the search parameters and store the results.
// execute the search
var itemSearch = await this.arcGISOnline.SearchItemsAsync(searchParameters);
results = itemSearch.Results;
15. Run your app and test the search. Find web maps and feature services using search terms.
Next, you will display properties for the chosen portal item in the list, including a thumbnail image and item description.
Steps:
1. In MainPage.xaml, add an event handler for the ResultListBox control's SelectionChanged event, as shown in the
following example.
<ListBox x:Name="ResultListBox"
Margin="20,0"
MaxHeight="200"
SelectionChanged="ResultList_SelectionChanged">
2. Right-click ResultList_SelectionChanged in your XAML and choose Go To Definition in the context menu.
3. Before coding the ResultList_SelectionChanged handler, add the following function (ResetUI) to reset values for
several of the UI controls. You will call this function when a new selection is made in the results list to make sure the UI is in
sync with the currently chosen portal item.
private void ResetUI()
{
// clear UI controls
this.SnippetTextBlock.Text = "";
this.ThumbnailImage.Source = null;
this.ShowMapButton.IsEnabled = false;
}
4. Return to the ResultList_SelectionChanged function. Add the following code to call your new ResetUI function.
// clear UI controls
this.ResetUI();
5. Add the following code to store the chosen portal item in the private variable you defined previously
(selectedPortalItem). Return from the handler if the current item is null.
// store the currently selected portal item
this.selectedPortalItem = this.ResultListBox.SelectedItem as ArcGISPortalItem;
if (this.selectedPortalItem == null) { return; }
In the rest of the code in this function, you can safely assume that selectedPortalItem refers to a portal item.
6. The Snippet property on ArcGISPortalItem contains a brief description of the item in plain text. Add the following code
to show a description of the item if the snippet is not null.
// show the portal item snippet (brief description) in the UI
if (!string.IsNullOrEmpty(this.selectedPortalItem.Snippet))
{
this.SnippetTextBlock.Text = this.selectedPortalItem.Snippet;
}
Note: ArcGISPortalItem also provides a Description property, which provides information about
the item formatted as HTML.
7. A portal may or may not have a thumbnail image. Add the following code to display an image for the chosen portal item if the
ThumbnailUri property is not null.
// show a thumbnail for the selected portal item (if there is one)
if (this.selectedPortalItem.ThumbnailUri != null)
{
var src = new Windows.UI.Xaml.Media.Imaging.BitmapImage(this.selectedPortalItem.ThumbnailUri);
this.ThumbnailImage.Source = src;
}
8. Run your app and test the new code. Search for portal items and choose one in the list of results. A description and
thumbnail image displays on the page.
Steps:
1. Open your MainPage.xaml page in XAML view.
2. Add a click handler to ShowMapButton as shown in the following example.
<Button x:Name="ShowMapButton"
Content="Show Map"
Margin="5"
Width="150"
IsEnabled="False"
Click="ShowMapButton_Click"/>
3. Right-click ShowMapButton_Click in your XAML and choose Go To Definition in the context menu.
4. In MainPage.xaml.cs, add the async keyword to the ShowMapButton_Click event handler, as shown in the following
example.
private async void ShowMapButton_Click(object sender, RoutedEventArgs e)
Before coding the ShowMapButton_Click event handler, add code to enable the button only when a portal item of type web
map is chosen in the result list.
5. At the end of the ResultList_SelectionChanged event handler, add the code shown in the following example to enable
the ShowMapButton control when a web map type of portal item is chosen in the list.
// enable the show map button when a web map portal item is chosen
this.ShowMapButton.IsEnabled = (this.selectedPortalItem.Type == ItemType.WebMap);
You can now add code to the ShowMapButton_Click event handler with the assumption that a web map portal item is
currently chosen. The static FromPortalItemAsync method on the Esri.ArcGISRuntime.WebMap.WebMap class opens
a web map from a portal item. Use this method to get the web map represented by the currently chosen portal item in the list.
6. Return to ShowMapButton_Click and add the code shown in the following example to open the web map represented by
the chosen portal item.
// create a web map from the selected portal item
var webMap = await WebMap.FromPortalItemAsync(this.selectedPortalItem);
The WebMap class contains properties for accessing the basemap layers, operational layers, and tasks the map contains. To
display the entire map, load the web map into a WebMapViewModel object and reference its Map property.
Tip: For more information about the Model-View-ViewModel design pattern, for which the
WebMapViewModel is designed, refer to the Use the MVVM design pattern tutorial.
7. Add the code shown in the following example to create a new WebMapViewModel containing the web map. LoadAsync is a
static method on the WebMapViewModel class.
// load the web map into a web map view model
var webMapVM = await WebMapViewModel.LoadAsync(webMap, this.arcGISOnline);
8. Complete the ShowMapButton_Click event handler by adding the code in the following example to show the web map on
your page's MapView control.
// show the web map view model's map in the page's map view control
this.MyMapView.Map = webMapVM.Map;
9. Run your app. Search for web maps, select one in the result list, then click the Show Map button. The chosen web map
displays in your map view. Try searching the feature services. The Show Map button is not enabled when a feature service
portal item is chosen in the list.
Well done, you've completed the tutorial. For more examples of working with content from a portal, see the arcgis-runtime-samples-dotnet
repository on GitHub. For a fully functional portal viewer application built using the Model-View-ViewModel (MVVM) design pattern, see
the arcgis-portalviewer-dotnet repository.
Related Topics
Access the ArcGIS platform
Access portal content
Search portal content
Security
Prerequisites
This tutorial requires a supported version of Microsoft Visual Studio and ArcGIS Runtime SDK for .NET. See Install the SDK and System
requirements for more information.
Familiarity with Visual Studio and a basic understanding of XAML and C# or Visual Basic .NET (VB .NET) is recommended.
Tip: ArcGIS Runtime SDK for .NET provides a project template for creating your mapping app, called
ArcGIS Runtime 10.2.7 for .NET App. Creating your project from the template will add the
appropriate references and a page with a map view containing a single base layer. In this tutorial,
you'll build your app from a blank template.
4. Choose a folder location for your new project and name it Geocoding.
Note: In order for your app to build, you need to specify a build target for the project. The default value of
Any CPU will not work and is why the new references are shown with a yellow warning icon.
You will now specify a build platform for the app.
9. Choose BUILD > Configuration Manager.
10. Choose x86 in the Active solution platform drop-down menu. This will target a 32-bit platform for the app.
Steps:
To use the ESRI.ArcGISRuntime library in the XAML designer, you must first make the required reference to its XML
namespace.
1. Open the MainPage.xaml file in the Visual Studio designer.
2. Go to the XAML view of the designer, and add the following XML namespace reference to the Page XAML element. Visual
Studio offers IntelliSense to help complete the URL portion of the statement.
xmlns:esri="using:Esri.ArcGISRuntime.Controls"
xmlns:layers="using:Esri.ArcGISRuntime.Layers"
Next, you'll add a MapView control to the window and define a layer to display.
3. Add the following XAML inside the <Grid> element to define a new MapView control on the page. The map will contain the
World Streets Map basemap layer from ArcGIS Online and an empty graphics layer for displaying geocode results.
<esri:MapView x:Name="MyMapView">
<esri:Map x:Name="MyMap">
<layers:ArcGISTiledMapServiceLayer ID="Streets"
ServiceUri="http://services.arcgisonline.com/arcgis/rest/services/World_Street_Map/MapServer"/>
<layers:GraphicsLayer ID="GeocodeResults"/>
</esri:Map>
</esri:MapView>
Note: In the previous XAML, a value is provided for each layer's ID property. This simplifies referring to
the layer programmatically. For the MapView and Map controls, the x:Name property serves the
same purpose.
Tip: In addition to the World imagery map, ArcGIS Online provides basemaps of streets, topographic
data, historical maps, and many others. Visit Living Atlas of the World to browse some of the
available basemaps. If you find a basemap you'd like to use in your app, you can copy the service
URI from its description page.
Steps:
1. Add the following XAML to define a simple UI for address input. It's important to add this XAML below the code for your
MapView element to ensure the address controls display on top of the map.
<StackPanel Orientation="Vertical"
HorizontalAlignment="Left" VerticalAlignment="Top" Background="Blue">
<StackPanel Orientation="Horizontal">
<TextBox x:Name="AddressTextBox" Text="1145 17th St NW, Washington, DC 20036" Margin="10,0"/>
<Button x:Name="FindAddressButton" Content="Find"/>
</StackPanel>
</StackPanel>
2. Add the following XAML to the Button element to define a handler for its Click event. When prompted by Visual Studio
IntelliSense, press the Tab key to create the new event handler, which will be called FindAddressButton_Click as
shown in the following code example:
<Button x:Name="FindAddressButton" Content="Find" Click="FindAddressButton_Click"/>
3. Right-click the text FindAddressButton_Click in the designer and choose Go To Definition from the context menu that
appears.
The code view opens for your page, to the new FindAddressButton_Click handler.
Steps:
1. At the top of the MainPage.xaml.cs file, add the following using statements to bring in required geocoding and geometry
functionality.
using Esri.ArcGISRuntime.Tasks.Geocoding;
using Esri.ArcGISRuntime.Geometry;
2. Return to the FindAddressButton_Click event handler and add the following code to create an OnlineLocatorTask
object. The constructor takes two arguments: the URI for the geocode service and a token (required for secured services).
var uri = new Uri("http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer");
var token = String.Empty;
var locator = new OnlineLocatorTask(uri, token);
Finding an address using the OnlineLocatorTask requires an OnlineLocatorFindParameters object, which holds all
relevant information for the address search.
3. Add the following code to define the find parameter:
var findParams = new OnlineLocatorFindParameters(AddressTextBox.Text);
findParams.OutSpatialReference = MyMapView.SpatialReference;
findParams.SourceCountry = "US";
The Text property defines the address to locate. By setting the OutSpatialReference property to that of the MapView,
you'll get results that can be used in the map without having to reproject. SourceCountry is an optional property that can
be set to restrict address searches to a specific country (which can improve performance). This value can be set using the
ISO country code, a list of which can be found at www.iso.org.
4. Call the FindAsync method on the locator by adding the following code:
var results = await locator.FindAsync(findParams, new System.Threading.CancellationToken());
6. After the call to FindAsync completes, check for results. If there is at least one result (address match), you'll get the
location of the first match, as shown in the following code example:
if (results.Count > 0)
{
var firstMatch = results[0].Feature;
var matchLocation = firstMatch.Geometry as MapPoint;
}
7. Continue the code in the if statement with the following code to build an Envelope that surrounds the location. Zoom the
map to that extent by passing the envelope to SetViewAsync.
var matchExtent = new Envelope(matchLocation.X - 100,
matchLocation.Y - 100,
matchLocation.X + 100,
matchLocation.Y + 100);
await MyMapView.SetViewAsync(matchExtent);
The Envelope is created by subtracting 100 meters from the location's minimum X and Y values and adding 100 meters to
the maximum X and Y values.
8. Run the app and test the Find button.
Tip: If you want the user to review all matches, you can modify the app to show the list of results along with the
value of each candidate's Score property (an int between 0 and 100).
Add a point graphic at the address location
Your app currently zooms to the extent of a match but does not show its precise location. In the following steps, you'll add code to place a
point graphic to indicate the location of the match.
Steps:
1. At the top of your MainPage.xaml.cs code file, add the following using statements to bring in the required
Esri.ArcGISRuntime.Symbology and Esri.ArcGISRuntime.Layers namespaces.
using Esri.ArcGISRuntime.Symbology;
using Esri.ArcGISRuntime.Layers;
2. Return to the FindAddressButton_Click event handler. Below the line that instantiates the matchLocation variable,
add the following code to instantiate a new PictureMarkerSymbol for displaying the point. Set the source of the marker's
picture using the SetSourceAsync method with the await keyword.
var matchSym = new PictureMarkerSymbol();
var pictureUri = new Uri("http://static.arcgis.com/images/Symbols/Basic/GreenStickpin.png");
await matchSym.SetSourceAsync(pictureUri);
Tip: The Static Images topic in the API reference contains a list of available images hosted on
static.arcgis.com.
3. Create a new Graphic. Pass in the geometry and symbol to the constructor.
var matchGraphic = new Graphic(matchLocation, matchSym);
4. Get a reference to the graphic layer you defined for the map, and add the new graphic.
var graphicsLayer = MyMap.Layers["GeocodeResults"] as GraphicsLayer;
graphicsLayer.Graphics.Add(matchGraphic);
5. Test the app. In addition to zooming to the match location, you'll also see a pushpin marker at the match location.
6. Instead of an address, search for a well known place name. Try Smithsonian or White House, for example.
The world geocoding service allows you to find locations by providing an address orfor well known placesa name.
Steps:
1. Open the MainPage.xaml page and add a new Button called ReverseGeocodeButton to your existing XAML as shown
in the following code example:
<StackPanel Orientation="Vertical"
HorizontalAlignment="Left" VerticalAlignment="Top" Background="Blue">
<StackPanel Orientation="Horizontal">
<TextBox x:Name="AddressTextBox" Text="1145 17th St NW, Washington, DC 20036" Margin="10,0"/>
<Button x:Name="FindAddressButton" Content="Find" Click="FindAddressButton_Click"/>
</StackPanel>
<Button x:Name="ReverseGeocodeButton" Content="Reverse Geocode"/>
</StackPanel>
2. Add a click handler to the button. When prompted by IntelliSense, create a New Event Handler named
ReverseGeocodeButton_Click.
<Button x:Name="ReverseGeocodeButton" Content="Reverse Geocode" Click="ReverseGeocodeButton_Click"/>
3. Right-click the ReverseGeocodeButton_Click handler in the XAML, and choose Go To Definition in the context menu
that appears.
The MapView control has an associated Editor that is accessible from the Editor property. In addition to helping you
configure editing functionality, the Editor class provides methods for obtaining geometry from the user. You'll use the
RequestPointAsync method on the Editor to get a point to reverse geocode from the user.
4. Start the ReverseGeocodeButton_Click event handler with the following code to get a point from the user:
var mapPoint = await MyMapView.Editor.RequestPointAsync();
Because the call to RequestPointAsync is asynchronous, you must use the await keyword. This means that the function
that contains the call must also be marked with the async keyword.
5. Add the async keyword to the definition of the ReverseGeocodeButton_Click handler.
private async void ReverseGeocodeButton_Click(object sender, RoutedEventArgs e)
RequestPointAsync returns the user's map click as a MapPoint object. Because the map is in a Web Mercator spatial
reference, and the OnlineLocatorTask you're using requires geographic points (decimal degrees of longitude and
latitude), you need to project the point before performing the reverse geocode.
6. Add the following code (after the line that instantiates the mapPoint variable) to project the user's point to geographic units:
var mapPointGeo = GeometryEngine.Project(mapPoint, SpatialReferences.Wgs84) as MapPoint;
7. Create an OnlineLocatorTask using the same code you wrote for the geocoding operation, as shown in the following
code example:
var uri = new Uri("http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer");
var token = String.Empty;
var locator = new OnlineLocatorTask(uri, token);
8. Use the OnlineLocatorTask to perform the reverse geocode on the geographic point by calling its
ReverseGeocodeAsync method.
var addressInfo = await locator.ReverseGeocodeAsync(mapPointGeo, 100, new System.Threading.CancellationToken());
The ReverseGeocdodeAsync method returns a LocatorReverseGeocodeResult. The information about the address is
available in the AddressFields property.
9. Build the estimated reverse geocoding address string by reading values in the LocatorReverseGeocodeResult
AddressFields property, which is a dictionary of strings.
var address = addressInfo.AddressFields["Address"] + ", " +
addressInfo.AddressFields["City"] + ", " +
addressInfo.AddressFields["Region"] + " " +
addressInfo.AddressFields["Postal"];
11. Test the app. Zoom to a portion of the map where streets are visible, click the Reverse Geocode button, and click near a
street to see an interpolated address.
In this tutorial, you used the OnlineLocatorTask to perform geocoding and reverse geocoding operations using an ArcGIS for Server
geocode service. To perform the same operations using a locator on the local file system, use the LocalLocatorTask class. To learn
about providing routing functionality and detailed driving directions using the ArcGIS Runtime SDK for .NET, see the Get driving directions
tutorial.
Related Topics
Get driving directions
Search for places
Prerequisites
This tutorial requires a supported version of Microsoft Visual Studio and ArcGIS Runtime SDK for .NET. Refer to the appropriate topics in
the guide for information on installing the SDK and system requirements.
Familiarity with Visual Studio and a basic understanding of XAML and C# or Visual Basic .NET (VB .NET) is recommended.
Note: You must have an ArcGIS Online organizational account in order to connect to the world route service used
to complete this tutorial. Visit the Esri website for information about pricing and trial subscriptions.
Create a Windows Store app
You'll use Visual Studio to create a Windows Store app.
Steps:
1. Open a supported version of Microsoft Visual Studio.
2. Choose File > New > Project (or click New Project on the Start page) to create a project.
3. Click Store Apps > Windows Apps > Blank App (Windows) in the New Project dialog box (you can create your project in
either C# or VB .NET).
Note: Visual Studio 2015 organizes project types slightly differently. You'll find Store projects under
Windows 8 > Windows
Tip: ArcGIS Runtime SDK for .NET provides a project template for creating your mapping app, called
ArcGIS Runtime 10.2.7 for .NET App. Creating your project from the template will add the
appropriate references and a page with a map view containing a single base layer. In this tutorial,
you'll build your app from a blank template.
4. Choose a folder location for your new project and name it DrivingDirections.
Note: In order for your app to build, you need to specify a build target for the project. The default value of
Any CPU will not work and is why the new references are shown with a yellow warning icon.
You will now specify a build platform for the app.
9. Choose BUILD > Configuration Manager.
10. Choose x86 in the Active solution platform drop-down menu. This will target a 32-bit platform for the app.
Steps:
To use the ESRI.ArcGISRuntime library in the XAML designer, you must first make some required references to XML
namespaces.
1. Open the MainPage.xaml file in the Visual Studio designer.
2. Go to the XAML view of the designer, and add the following XML namespace reference to the Page XAML element. Visual
Studio offers IntelliSense to help complete the URL portion of the statement.
xmlns:esri="using:Esri.ArcGISRuntime.Controls"
xmlns:layers="using:Esri.ArcGISRuntime.Layers"
Next, you'll add a Map control to the window and define a layer to display.
3. Add the following XAML inside the <Grid> element to define a new MapView control on the page. The map will contain a
Map displaying the World Streets Map basemap layer from ArcGIS Online and an empty graphics layer for showing route
results.
<esri:MapView x:Name="MyMapView" >
<esri:Map x:Name="MyMap">
<layers:ArcGISTiledMapServiceLayer ID="Streets"
ServiceUri="http://services.arcgisonline.com/arcgis/rest/services/World_Street_Map/MapServer"/>
<layers:GraphicsLayer ID="RouteResults"/>
</esri:Map>
</esri:MapView>
Note: In the previous XAML, a value is provided for each layer's ID property. This simplifies referring to
the layer programmatically. For the MapView and Map controls, the x:Name property serves the
same purpose.
Tip: In addition to the World imagery map, ArcGIS Online provides basemaps of streets, topographic
data, historical maps, and many others. Visit Living Atlas of the World to browse some of the
available basemaps. If you find a basemap you'd like to use in your app, you can copy the service
URI from its description page.
Steps:
1. Add the following XAML immediately inside the Grid element that contains your map. This will divide the Grid into four
sections defined by two rows and two columns.
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="300"/>
</Grid.ColumnDefinitions>
To define an element's location within your grid, you must set the Grid.Row and Grid.Column attached properties. These
properties default to 0, which means an element will appear in the first column of the first row (upper-left cell) unless
otherwise specified.
2. Move your MapView control to the correct position in the grid by setting its Grid.Row and Grid.Column properties as
shown in the following code example:
Tip: Since the default value is 0 for Grid.Row and Grid.Column, these properties do not need to be
explicitly set for controls appearing in those positions. You can set them to make your XAML
more readable for those not aware of the default values.
3. Inside the same Grid, below the XAML that defines your MapView, add the following XAML to define the address input
portion of the UI. This will create a StackPanel element with TextBox controls for addresses and a Button element to
initiate execution of the route.
<StackPanel Orientation="Horizontal" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2">
<TextBox x:Name="FromTextBox" Text="380 New York Street, Redlands CA" Width="300" Margin="5"/>
<TextBox x:Name="ToTextBox" Text="277 N Ave Caballeros, Palm Springs CA" Width="300" Margin="5"/>
<Button x:Name="GetDirectionsButton" Content="Get Directions" Margin="5"/>
</StackPanel>
The Grid.RowSpan and Grid.ColumnSpan properties allow an element to occupy multiple rows or columns. The
StackPanel occupies the entire top row of the grid (two columns).
4. Add the following XAML to define the driving directions portion of the UI. This takes up the right side of the app's UI,
immediately to the right of the Map. It contains TextBlock controls to display the total route time and distance, as well as a
ScrollViewer and TextBlock for showing the step-by-step driving directions.
<StackPanel Orientation="Vertical" Grid.Row="1" Grid.Column="1" Margin="10">
<TextBlock x:Name="RouteDistance"/>
<TextBlock x:Name="RouteTime"/>
<ScrollViewer HorizontalScrollBarVisibility="Auto" Height="250" Margin="10">
<TextBlock x:Name="DirectionsTextBlock"/>
</ScrollViewer>
</StackPanel>
Steps:
1. Add a click handler to the XAML definition of the GetDirectionsButton element. When prompted by IntelliSense, create
a New Event Handler called GetDirectionsButton_Click as shown in the following code example:
<Button x:Name="GetDirectionsButton" Content="Get Directions" Margin="5"
Click="GetDirectionsButton_Click"/>
2. Right-click the XAML for the GetDirectionsButton_Click event handler, and choose Go To Definition from the
context menu.
Visual Studio switches to code view and displays the GetDirectionsButton_Click function.
3. Add the async keyword to the definition of your GetDirectionsButton_Click event handler as shown in the following
code example. Because you're calling asynchronous methods using the await keyword, the containing function must be
defined with async.
private async void GetDirectionsButton_Click(object sender, RoutedEventArgs e)
Before fleshing out the code for GetDirectionsButton_Click, you'll add a function that asynchronously geocodes an
address that's passed in. You'll then return to the GetDirectionsButton_Click handler and call your function to get the
from and to locations for the route.
4. Add the following using statements at the top of your MainPage.xaml.cs module for namespaces in the ArcGIS Runtime
assembly that you'll need.
using Esri.ArcGISRuntime.Geometry;
using Esri.ArcGISRuntime.Layers;
using Esri.ArcGISRuntime.Symbology;
using Esri.ArcGISRuntime.Tasks.Geocoding;
using Esri.ArcGISRuntime.Tasks.NetworkAnalyst;
The previous function is defined as async, which means it must return void or a value of Task or Task<T>. The
FindAddress function uses an OnlineLocatorTask to asynchronously locate the first match for the address provided. If
a match is found, its Geometry is used to create a Graphic. A Name attribute is added and populated with the value of the
address string. This is important for your app, because the driving directions returned from the route task will refer to the
stops using a Name attribute (if it exists). The function returns the Graphic (which will be null if a match was not found).
To learn more about geocoding, see the Add geocoding to your app tutorial.
6. Return to the GetDirectionsButton_Click event handler. Add two calls to the FindAddress function to get the start
and end locations using the address strings provided by the user as shown in the following code example:
var from = await this.FindAddress(this.FromTextBox.Text);
var to = await this.FindAddress(this.ToTextBox.Text);
7. Below the code that gets the from and to locations, create a try catch block similar to the following. This code checks
for the required route points and the graphics layer for displaying results. If a required object is null, the appropriate
exception message is shown in the driving directions panel.
try
{
if (from == null)
{
throw new Exception("Unable to find a match for '" + this.FromTextBox.Text + "'.");
}
if (to == null)
{
throw new Exception("Unable to find a match for '" + this.ToTextBox.Text + "'.");
}
// get the RouteResults graphics layer; add the from/to graphics
var routeGraphics = MyMap.Layers["RouteResults"] as GraphicsLayer;
if (routeGraphics == null)
{
throw new Exception("A graphics layer named 'RouteResults' was not found in the map.");
}
8. Add the following code immediately below the comment that says // code here to show address locations on
the map. This adds the from address location to the results graphics layer as a green circle and the to address location as a
red circle.
var fromMapPoint = GeometryEngine.Project(from.Geometry, new SpatialReference(102100));
var toMapPoint = GeometryEngine.Project(to.Geometry, new SpatialReference(102100));
var fromSym = new SimpleMarkerSymbol { Style = SimpleMarkerStyle.Circle, Size = 16, Color = Windows.UI.Colors.Green };
var toSym = new SimpleMarkerSymbol { Style = SimpleMarkerStyle.Circle, Size = 16, Color = Windows.UI.Colors.Red };
The previous code projects the address match points from a geographic spatial reference (required for the
OnlineRouteTask) to Web Mercator (to match the map) before creating and adding the graphics.
9. Test the functionality you've added to this point. Run the app and click the Get Directions button with the default address
values in the text boxes. You'll see graphics added to the southern California region of the map. Zoom in and you'll see both
graphics as shown in the following screen capture:
Note: You must have an ArcGIS Online organizational account in order to connect to the world route service used
in this tutorial. Visit the Esri website for information about pricing and trial subscriptions.
Steps:
1. Add the following using statements to the top of your code module to bring in some security-related classes.
using Esri.ArcGISRuntime.Security;
using Esri.ArcGISRuntime.Http;
2. Create two new string variables to hold your ArcGIS Online organizational username and password, as shown in the
following code (replace the values with your login info). Add these lines immediately inside your class definition.
private const string ArcGISOnineUser = "MyUsername"; // update value with your username
private const string ArcGISOninePassword = "my-P@SSw0rd"; // update value with your password
3. Add the following function to serve as a ChallengeHandler. When a request for a secured service is encountered, this
function will handle getting credentials for a user that can connect to the service.
private async Task<Credential> CreateHardCodedCredentialAsync(CredentialRequestInfo requestInfo)
{
Credential cred = null;
try
{
var options = new GenerateTokenOptions();
options.TokenAuthenticationType = TokenAuthenticationType.ArcGISToken;
cred = await IdentityManager.Current.GenerateCredentialAsync(requestInfo.ServiceUri, ArcGISOnineUser, ArcGISOninePassword, options);
}
catch (ArcGISWebException webEx)
{
// couldn't generate a token, probably a bad login
return cred;
}
This function will attempt to obtain credentials for any secured services with the username and password provided in your
code. If the login fails, an ArcGISWebException is thrown. For more information about using ArcGIS Token authentication
(including how to prompt users for their credentials), see the Use ArcGIS token authentication topic.
4. Next, set the app to use the challenge handler function above by assigning the IdentityManager.ChallengeHandler
property as shown in the following example. This code should go in your class constructor, immediately following the call to
InitializeComponent.
You are now able to connect to the secured ArcGIS Online world routing service to solve routes and get driving directions.
Steps:
1. Continue the code in your GetDirectionsButton_Click function by adding the following code to create an
OnlineRouteTask. Add this code immediately after the code that adds the geocoded point graphics to the map.
var uri = new Uri(
"http://route.arcgis.com/arcgis/rest/services/World/Route/NAServer/Route_World"
);
var routeTask = new OnlineRouteTask(uri);
The OnlineRouteTask requires an ArcGIS Network Analyst service, whose URI is passed into the constructor. The
Route_World service is a secured ArcGIS Online service available to users with an organizational account.
2. Add the following code to set route parameters using the RouteParameters class:
var routeParams = await routeTask.GetDefaultParametersAsync();
routeParams.OutSpatialReference = MyMapView.SpatialReference;
routeParams.DirectionsLengthUnit = LinearUnits.Miles;
routeParams.ReturnDirections = true;
The RouteParameters object is used to specify properties such as the output spatial reference for route result features,
the length unit to use in driving directions, whether certain restrictions should be placed on routing (for example, no u-turns),
barriers to consider, and so on. It also holds a Stops collection, which you'll set using your geocoded points.
3. Add the following code to create the required stops for the RouteParameters. Make sure you use the graphics in
geographic units (from and to variables), rather than those you projected to Web Mercator for display on the map.
var stopGraphics = new List<Graphic>();
stopGraphics.Add(from);
stopGraphics.Add(to);
routeParams.SetStops(stopGraphics);
4. Solve the route by calling SolveAsync. If no results are returned, you'll throw an exception to display in the app. Otherwise,
get a reference to the first (only) route in the results.
var routeResult = await routeTask.SolveAsync(routeParams);
if (routeResult == null || routeResult.Routes == null || routeResult.Routes.Count == 0)
{
throw new Exception("Unable to solve the route.");
}
5. Get the result RouteFeature, create a new Graphic using the route geometry and a new SimpleLineSymbol.
var routeFeature = firstRoute.RouteFeature;
var routeSym = new SimpleLineSymbol
{
Color = Windows.UI.Colors.Navy,
Style = SimpleLineStyle.Dash,
Width = 2
};
var routeGraphic = new Graphic(routeFeature.Geometry, routeSym);
6. Add the route graphic to the results layer, and set the map view to the extent of the route.
routeGraphics.Graphics.Add(routeGraphic);
await MyMapView.SetViewAsync(routeGraphic.Geometry.Extent);
7. Test the functionality you've coded to this point. Run the app, and click the Get Directions button with the default address
values. The map zooms to the extent of the resulting route as shown in the following screen capture:
Steps:
1. Continue your code in GetDirectionsButton_Click immediately below the line that zooms the map to the extent of the
route. Begin by defining the following variables to store driving directions as well as information about the route:
var directionsBuilder = new System.Text.StringBuilder();
var totalMiles = 0.0;
var totalMinutes = 0.0;
var step = 1;
2. Create the following loop to iterate over each RouteDirection in the RouteDirections collection:
foreach (var d in firstRoute.RouteDirections)
{
}
3. Inside the foreach loop, add the following code to append the current directions text to the directionsBuilder variable
(StringBuilder):
directionsBuilder.AppendFormat("{0} \t {1}", step.ToString(), d.Text + "\n");
step++;
This code will append a step number, followed by a TAB, followed by the directions text, and finally a new line. The step
variable is then incremented.
4. Add the following code inside the loop to keep a running total of the segment length (miles) and time (minutes):
totalMiles += d.GetLength(LinearUnits.Miles);
totalMinutes += d.Time.TotalMinutes;
5. Add the following code outside of the loop to update the app UI with the route info and driving directions:
this.RouteDistance.Text = totalMiles.ToString("0.00") + " miles";
this.RouteTime.Text = totalMinutes.ToString("0.00") + " minutes";
this.DirectionsTextBlock.Text = directionsBuilder.ToString();
6. Test the app again. Click the Get Directions button with the default address values. An image similar to the following
displays:
In this tutorial, you used the OnlineRouteTask to perform routing operations using an ArcGIS for Server Network Analyst service. To
perform the same operations using a network dataset on the local file system, use the LocalRouteTask class. To learn more about
using geocode functionality with ArcGIS Runtime SDK for .NET, see the Add geocoding to your app tutorial.
Related Topics
Add geocoding to your app
Search for places
Services patternDatasets (features or tiles) are downloaded from configured services to generate local versions of the data. This
pattern lets multiple offline users edit the same data layers and synchronize their edits back to the service later (when an Internet
connection is available, for example). When more than one user is editing the same feature and the edits conflict, the last edit
committed overrides the others.
The desktop pattern allows you to deliver the data with your app, which works well when you know exactly what data the app needs.
Feature data provisioned using the desktop pattern is read-only, so if editing is required in your app, you must use the services pattern to
create the offline features. The services pattern provides local copies of the data directly from the service, and allows you to filter the
features you need according to layers and map extent. Most importantly, local datasets copied from the service allow editing of features.
Those edits can be synchronized with the service when needed. Be aware that the services pattern may require a lot of time and
bandwidth to produce local copies of large datasets, especially a local map tile cache.
A hybrid solution for working with local data is often a good approach. Local feature data can be obtained using the services pattern to
ensure the data are current, editable, and can be synchronized with the service. Local tile caches can be provisioned using the desktop
pattern to ensure the large datasets are available when needed, without requiring the user to wait for them to generate and download.
License: An app licensed at the Basic level can include viewing offline basemaps and feature data from a runtime
geodatabase. You must license your app at the Standard level if it includes any of the following functionality:
offline editing, syncing offline edits with an upload, offline routing, and offline geocoding. See License your
app for more information on license levels.
This tutorial introduces you to techniques that can give your user a seamless experience when working with an app in connected and
offline modes. Specifically, you will learn how to:
Create a local database of features using the services pattern.
Create a local tile package.
Access local datasets for display.
Switch between online and local data sources in the map.
Prerequisites
This tutorial requires a supported version of Microsoft Visual Studio and ArcGIS Runtime SDK for .NET. See Install the SDK and System
requirements for more information.
Familiarity with Visual Studio and a basic understanding of XAML, and C# or Visual Basic .NET (VB .NET) is recommended.
Tip: ArcGIS Runtime SDK for .NET provides a project template for creating your mapping app, called
ArcGIS Runtime 10.2.7 for .NET App. Creating your project from the template will add the
appropriate references and a page with a map view containing a single base layer. In this tutorial,
you'll build your app from a blank template.
4. Choose a folder location for your new project and name it OfflineApp.
Note: For your app to build, specify a build target for the project. The default value of Any CPU will not
work and is why the new references show with a yellow warning icon.
You will now specify a build platform for the app.
9. Choose BUILD > Configuration Manager.
10. Choose x86 in the Active solution platform drop-down menu. This targets a 32-bit platform for the app.
Begin by creating a basic UI for your app. To use the classes in the ArcGIS Runtime API, define XML namespace references in
MainPage.xaml.
Steps:
1. Open the MainPage.xaml page in XAML view.
2. Add the following XAML in the Page element of MainPage.xaml to define an XML namespace reference for the ArcGIS
Runtime API controls.
xmlns:esri="using:Esri.ArcGISRuntime.Controls"
3. Inside the Grid element on the page, add the XAML below to create an empty MapView control. Assign the name
MyMapView to the control so you can reference it in your code behind.
<esri:MapView x:Name="MyMapView">
<esri:Map>
</esri:Map>
</esri:MapView>
Depending on connectivity, at runtime your MapView displays maps and layers from online or local sources.
Create the UI
The UI for your app have controls for creating local versions of the online data sources (map tiles and features), and for switching between
online and local data sources. The XAML to define the app's UI has been created for you.
Steps:
1. Copy the following XAML and paste it into your MainPage.xaml page to create your app's UI. Paste it immediately after the
XAML that defines your map view.
<Canvas
Width="370" Height="197"
HorizontalAlignment="Left" VerticalAlignment="Bottom"
Margin="20,0,0,143" >
<Border x:Name="ToolsPanel"
CornerRadius="10"
Background="DarkGray" Opacity="0.85"
Width="370"
Canvas.Top="0">
<Grid x:Name="Controls"
Opacity="1"
Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<RadioButton x:Name="UseOnlineDataOption"
Grid.Row="0" Grid.Column="0"
Click="DataOptionChecked"
Content="Online Data"
HorizontalAlignment="Center" VerticalAlignment="Center"
IsChecked="True"/>
<RadioButton x:Name="UseLocalDataOption"
Grid.Row="0" Grid.Column="1"
Click="DataOptionChecked"
Content="Local Data"
HorizontalAlignment="Center" VerticalAlignment="Center" />
<StackPanel Orientation="Horizontal"
Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3"
Margin="0,10,0,5">
<Button x:Name="GenerateLocalGeodatabaseButton"
Click="GetFeatures"
ToolTipService.ToolTip="Generate local geodatabase"
Margin="0,0,3,0" >
<Image Source="http://static.arcgis.com/images/Symbols/Cartographic/esriCartographyMarker_60_White.png" Width="20" Height="20">
<Image.RenderTransform>
<RotateTransform Angle="180" CenterX="10" CenterY="10"/>
</Image.RenderTransform>
</Image>
</Button>
<TextBlock Text="Local features: " VerticalAlignment="Center" FontSize="14"/>
<TextBlock x:Name="LocalDataPathTextBlock"
Text="< none >" VerticalAlignment="Center" FontSize="14"/>
</StackPanel>
<StackPanel Orientation="Horizontal"
Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="3"
Margin="0,5,0,10">
<Button x:Name="GenerateLocalTilesButton"
Click="GetTiles"
ToolTipService.ToolTip="Generate local tiles"
Margin="0,0,3,0" >
<Image Source="http://static.arcgis.com/images/Symbols/Cartographic/esriCartographyMarker_60_White.png" Width="20" Height="20">
<Image.RenderTransform>
<RotateTransform Angle="180" CenterX="10" CenterY="10"/>
</Image.RenderTransform>
</Image>
</Button>
<TextBlock Text="Local tiles: " VerticalAlignment="Center" FontSize="14"/>
<TextBlock x:Name="LocalTilesPathTextBlock"
Text="< none >" VerticalAlignment="Center" FontSize="14"
Margin="10,0"/>
</StackPanel>
<StackPanel x:Name="StatusPanel"
Grid.Row="5" Grid.Column="0" Grid.ColumnSpan="3"
Orientation="Vertical"
Visibility="Collapsed"
Margin="0,10">
<ListBox x:Name="StatusMessagesList"
Width="350" Height="80"
ScrollViewer.VerticalScrollBarVisibility="Visible"/>
<ProgressBar x:Name="StatusProgressBar"
Width="350" Height="5"/>
</StackPanel>
</Grid>
</Border>
</Canvas>
Many of the controls in the preceding XAML refer to event handlers that do not exist in your code behind.
2. Create stubs in your code behind for the event handlers referenced in your UI's XAML by copying the following code into
your MainPage.xaml.cs file. Some of the handlers require the async keyword.
Tip: You can create event handlers for your XAML controls by right-clicking the name of a handler and
clicking Go to definition in the context menu. If the handler does not exist, Visual Studio creates
it for you.
Start by adding some required using statements, variables, and an event handler for the map loaded event.
Steps:
1. Open the MainPage.xaml.cs code behind.
2. Add the following using statements at the top of the code module for additional namespaces you'll require.
using Esri.ArcGISRuntime.Controls;
using Esri.ArcGISRuntime.Data;
using Esri.ArcGISRuntime.Geometry;
using Esri.ArcGISRuntime.Http;
using Esri.ArcGISRuntime.Layers;
using Esri.ArcGISRuntime.Tasks.Offline;
using System.Threading;
using System.Threading.Tasks;
using Windows.UI.Popups;
using Windows.Storage;
using Windows.UI.Core;
3. Inside the class definition, add the following variable declarations. These variables contain the information you need to load
layers from online or local sources.
private const string basemapUrl = "http://sampleserver6.arcgisonline.com/arcgis/rest/services/World_Street_Map/MapServer";
private const string operationalUrl = "http://sampleserver6.arcgisonline.com/arcgis/rest/services/Sync/SaveTheBaySync/FeatureServer/0";
private string localTileCachePath;
private string localGeodatabasePath;
4. In the class constructor, create a handler for the MyMapView.Loaded event. When prompted, click the Tab key to have
Visual Studio generate the stub for the handler. Your code should look like the following.
public MainPage()
{
InitializeComponent();
MyMapView.Loaded += MyMapView_Loaded;
}
The MyMapView_Loaded handler calls a function that attempts to load online layers.
5. Create a new async function called TryLoadOnlineLayers. Inside the function, add a try block that catches three types
of exception: Esri.ArcGISRuntime.Http.ArcGISWebException, System.Net.Http.HttpRequestException,
and System.Exception as shown in the following code.
var messageDialog = new MessageDialog("Unable to load online layers: credentials may be required", "Load Error");
messageDialog.ShowAsync();
}
catch (System.Net.Http.HttpRequestException httpExp)
{
// not connected? server down? wrong URI?
var messageDialog = new MessageDialog("Unable to load online layers: check your connection and verify service URLs", "Load Error");
messageDialog.ShowAsync();
}
catch (Exception exp)
{
// other problems ...
var messageDialog = new MessageDialog("Unable to load online layers: " + exp.Message, "Load Error");
messageDialog.ShowAsync();
}
}
By handling exceptions in your try block from specific to general, you can better identify problems encountered when
accessing online services. An ArcGISWebException is commonly thrown when access to a secured online service is
made without the proper credentials. An HttpRequestException may be thrown for a variety of network connectivity
problems, such as an incorrect URI or an unavailable server resource. Other problems are handled by catching the generic
System.Exception.
6. Inside the try block, add code to create two new layers: an ArcGISTiledMapServiceLayer to display a streets
basemap, and a FeatureLayer to display marine wildlife sightings from an online feature service. Give the
FeatureLayer an ID so you can find it in the map's layer collection later.
// create an online tiled map service layer, an online feature layer
var basemapLayer = new ArcGISTiledMapServiceLayer(new Uri(basemapUrl));
var operationalLayer = new FeatureLayer(new Uri(operationalUrl));
// give the feature layer an ID so it can be found later
operationalLayer.ID = "Sightings";
7. Initialize the layers by calling InitializeAsync. Since this is an asynchronous call, you must use the await keyword to
await the result. After initializing, check each layer's InitializationException property to see if initialization was
successful.
// initialize the layers
await basemapLayer.InitializeAsync();
await operationalLayer.InitializeAsync();
// see if there was an exception when initializing the layers, if so throw an exception
if (basemapLayer.InitializationException != null ||
operationalLayer.InitializationException != null)
{
// unable to load one or more of the layers, throw an exception
throw new Exception("Could not initialize layers");
}
8. If the layers were initialized without an exception, add them to the map.
// add layers
MyMapView.Map.Layers.Add(basemapLayer);
MyMapView.Map.Layers.Add(operationalLayer);
10. Run the app. If you have an Internet connection, you should see the online layers load.
Before you can create a local version of the map, create local datasets for the basemap (a local tile cache) and for the operational layer
(a local geodatabase table). To control the size of the datasets generated, only enable the generate tiles button when the user zooms in
to a smaller portion of the map.
Steps:
1. Add the following code in your page's constructor to handle the MyMapView.NavigationCompleted event. When a
navigation operation completes (the user pans or zooms in or out, in other words), the GenerateLocalTilesButton
control is only enabled if the user has zoomed to a reasonable extent for creating the tile cache.
public MainPage()
{
InitializeComponent();
2. Declare a private CancellationTokenSource variable at the top of your class to manage user requests to cancel cache
generation.
private CancellationTokenSource cancellationTokenSource;
3. The cache generation code goes in the GetTiles function, which is the event handler for the
GenerateLocalTilesButton.Click event. Start the code with a Try block. In the catch portion of the block, show the
exception in the messages list. Use a finally statement to reset the progress bar to zero.
private async void GetTiles(object sender, RoutedEventArgs e)
{
try
{
}
catch (Exception exp)
{
StatusMessagesList.Items.Clear();
StatusMessagesList.Items.Add("Unable to get local tiles: " + exp.Message);
}
finally
{
// reset the progress indicator
StatusProgressBar.Value = 0;
}
}
4. Start the code in the try block by showing the controls for reporting the status of the task. Add a message that reports the
cache is being requested.
5. Cancel any previously submitted tasks that might still be executing (in case the user clicked the button before an earlier
request was completed, for example). Create the CancellationTokenSource and CancellationToken for the current
request.
// cancel if an earlier call was made
if (cancellationTokenSource != null)
{
cancellationTokenSource.Cancel();
}
6. Create a new ExportTileCacheTask that uses the URL for the world street map service in your map.
// create a new ExportTileCacheTask to generate the tiles
var exportTilesTask = new ExportTileCacheTask(new Uri(basemapUrl));
There are two broad steps involved for creating a local tile cache from a service: 1) generate the tiles on the server, and 2)
download the tiles to the local device. The ExportTileCache class has methods for performing each of these tasks
individually (GenerateTileCacheAsync and DownloadTileCacheAsync). In the following steps, however, call a single
method, GenerateTileCacheAndDownloadAsync, that performs both steps.
ExportTileCachTask.GenerateTileCacheAndDownloadAsync requires the following parameters.
Generation options (GenerateTileCacheParameters)Defines the output format, map extent, and scale levels
to include in the cache.
Download options (DownloadTileCacheParameters)Specifies the location on the local disk, and whether or
not to overwrite an existing cache.
Check interval (TimeSpan)The interval at which to check the status of the cache generation.
Cancellation token (System.Threading.CancellationToken)Allows the task to be cancelled.
Progress callbacks (IProgress<T>)Callbacks to report progress for both cache generation and download
(optional).
7. Create a new GenerateTileCacheParameters object and define some options for the cache, such as the extent and
scale levels to create.
// define options for the new tiles (extent, scale levels, format)
var generateOptions = new GenerateTileCacheParameters();
generateOptions.Format = ExportTileCacheFormat.CompactCache;
generateOptions.GeometryFilter = MyMapView.Extent;
generateOptions.MinScale = 6000000.0;
generateOptions.MaxScale = 1.0;
Note: Since the MinScale and MaxScale values for the cache parameters are specified with the scale
denominator, the value of MinScale is always larger than the MaxScale value (a scale
numerator value of 1.0 is implied). In the previous code, the minimum scale is 1.0 /
6000000.0 = 0.00000017 and the maximum is 1.0 / 1.0 = 1.0.
8. Create a new DownloadTileCacheParameters object and define the location for the output file.
// download the tile package to the app's local folder
var outFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
var downloadOptions = new DownloadTileCacheParameters(outFolder);
9. Define a two-second interval for checking the status of the cache creation.
// check generation progress every two seconds
var checkInterval = TimeSpan.FromSeconds(2);
10. The optional IProgress<T> arguments report status while the task is running. Create one for the cache generation
progress (Progress<ExportTileCacheJob>) using the following code. In the callback handler, parse out the percentage
complete and update the progress bar. Other progress messages are added to the StatusMessageList for the user to
see.
12. Call ExportTileCacheTask.GenerateTileCacheAndDownloadAsync to create the local cache. Pass in the required
arguments created previously. Use the await keyword to await the result.
// generate the tiles and download them
var result = await exportTilesTask.GenerateTileCacheAndDownloadAsync(generateOptions,
downloadOptions,
checkInterval,
cancelToken,
creationProgress,
downloadProgress);
13. When the task completes, store the path to the local cache and report success to the user.
// when complete, store the path to the new local tile cache
this.localTileCachePath = result.OutputPath;
LocalTilesPathTextBlock.Text = this.localTileCachePath;
ToolTipService.SetToolTip(LocalTilesPathTextBlock, this.localTileCachePath);
// clear the working messages, report success
StatusProgressBar.Value = 100;
StatusMessagesList.Items.Clear();
StatusMessagesList.Items.Add("Local tiles created at " + this.localTileCachePath);
14. Run your app, zoom into an area, and test creating a local tile cache.
In the next section, you will follow similar steps to create a local geodatabase containing the features in the sightings layer.
Tip: You can sync enable your ArcGIS Online hosted feature services by checking Enable Sync in the
item properties.
The user will be able to create a copy of the features in the feature service and store them in a geodatabase locally. In the following
steps, you write code to create a local geodatabase for a single layer in the service and at the current map extent.
Steps:
1. The geodatabase generation code goes in the GetFeatures function, which is the event handler for the
GenerateLocalGeodatabaseButton.Click event. Start the code with a try block as shown in the following example.
private async void GetFeatures(object sender, RoutedEventArgs e)
{
try
{
}
catch (Exception ex)
{
}
}
2. Inside the try portion of the block, show the status controls, add a message that the generate geodatabase job has been
submitted, and show the progress bar.
// show the status controls
StatusPanel.Visibility = Visibility.Visible;
StatusMessagesList.Items.Add("Submitting generate geodatabase job ...");
StatusProgressBar.IsIndeterminate = true;
StatusProgressBar.IsEnabled = true;
Note: The IsIndeterminate setting for the ProgressBar control means that it continually scrolls to
show that an operation is working, as opposed to showing the percent complete.
3. In the catch portion of the block, show the exception in the messages list and reset the IsIndeterminate property of the
progress bar false.
catch (Exception ex)
{
StatusMessagesList.Items.Add("Unable to create offline database: " + ex.Message);
StatusProgressBar.IsIndeterminate = false;
}
4. Return to the try block. After the code to show the status controls, add code to cancel any previously submitted jobs that
may be running and to create a new CancellationToken for the current job.
// cancel if an earlier call was made
if (cancellationTokenSource != null)
{
cancellationTokenSource.Cancel();
}
A GeodatabaseSyncTask is created by passing in the URI for the feature service you want to work with. The feature service
must be sync enabled to create a local geodatabase.
5. Use the URL to the sightings layer to get the URL of the feature service by stripping off the layer index at the end ("/0").
// create a new GeodatabaseSyncTask with the uri of the feature service to pull from
var serverUrl = operationalUrl.Substring(0, operationalUrl.LastIndexOf('/'));
var uri = new Uri(serverUrl);
var getFeaturesTask = new GeodatabaseSyncTask(uri);
The GeodatabaseSyncTask.GenerateGeodatabaseAsync method creates the desired geodatabase on the server and
requires the following parameters.
Generation options (GenerateGeodatabaseParameters)Defines the output spatial reference, map extent, and
layers to include in the geodatabase.
Generate complete callbackA callback that executes when the geodatabase generation is complete. Use the
callback to see if generation was successful and to download the data locally.
Check interval (TimeSpan)The interval at which to check the status of the geodatabase generation.
Progress callback (IProgress<T>)A callback to report progress for geodatabase creation (optional).
Cancellation token (System.Threading.CancellationToken)Allows the task to be cancelled.
6. Create a GenerateGeodatabaseParameters and set the layers, extent, and spatial reference for the output
geodatabase.
// create parameters for the task: layers and extent to include, out spatial reference, and sync model
var layers = new List<int>(new int[1] { 0 }); // just get the first layer
var extent = MyMapView.Extent;
var getFeaturesParams = new GenerateGeodatabaseParameters(layers, extent)
{
OutSpatialReference = MyMapView.SpatialReference,
SyncModel = SyncModel.PerLayer
};
Note: The SyncModel property has two possible values: PerGeodatabase or PerLayer. This setting
controls the granularity of synchronization of edits with the service, managed either on a layer-by-
layer basis or for the geodatabase as a whole.
7. Create a two-second interval for checking the status of the job. Use a Progress<GeodatabaseStatusInfo> to show the
current status.
// check progress every two seconds
var checkInterval = TimeSpan.FromSeconds(2);
var creationProgress = new Progress<GeodatabaseStatusInfo>(p =>
{
this.StatusMessagesList.Items.Add(DateTime.Now.TimeOfDay.ToString() + ": " + p.Status);
});
The last thing required before generating the geodatabase is a callback handler to execute when the server job is complete.
The callback sees if the database was created successfully on the server, then downloads it locally.
8. Create a new function to act as the callback handler for the GenerateGeodatabaseAsync method. The function will be
asynchronous and take two arguments: a GeodatabaseStatusInfo and an Exception.
// provide a callback to execute when the GeodatabaseSyncTask completes (successfully or with an exception)
private async void GenerateFeaturesCompleteCallback(GeodatabaseStatusInfo statusInfo, Exception ex)
{
9. Start the callback function by checking for an exception. If an exception has occurred, report it to the user and return.
// if unsuccessful, report the exception and return
if (ex != null)
{
await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() => StatusMessagesList.Items.Add("An exception occurred: " + ex.Message));
return;
}
Caution: Because the callback may be executing on a thread other than the UI thread, you must use
Dispatcher.RunAsync to update elements in the UI, as shown in the preceding code. See
Threading considerations for more information.
10. If the geodatabase was generated without exceptions, download it using ArcGISHttpClient. The
GeodatabaseStatusInfo object passed into the callback provides the URI for the database.
// if successful, download the generated geodatabase from the server
var client = new ArcGISHttpClient();
var geodatabaseStream = client.GetOrPostAsync(statusInfo.ResultUri, null);
11. Create an output path for the geodatabase. Call it Wildlife.geodatabase and store it in the app's directory.
// create a path for the local geodatabase
12. Use a TaskFactory to create a new task to copy the database stream to the output file. Use Dispatcher.RunAsync to
update UI elements with the local geodatabase path when the copy completes.
14. Run your app, zoom into an area, and test creating a local geodatabase.
In the following steps, add code to switch the map between using online and local sources. When the app is in online mode, the map
displays the online data sources (services). When offline, display data from the local tile cache and geodatabase (if they've been
created).
Steps:
Previously, you created a function to load the online layers in your map (TryLoadOnlineLayers). You will now create the
equivalent code for loading local (offline) layers.
1. Create a new asynchronous function in your code behind (MainPage.xaml.cs) called TryLoadLocalLayers.
2. Add a try block and handle exceptions with a single catch block that displays a message to the user.
}
catch (Exception exp)
{
var messageDialog = new MessageDialog("Unable to load local layers: " + exp.Message);
messageDialog.ShowAsync();
}
}
3. Inside the try block, check to see that the local tiles and geodatabase exist. If they don't, throw an exception with the
appropriate message to the user.
if (string.IsNullOrEmpty(this.localGeodatabasePath))
{
throw new Exception("Local features do not yet exist. Please generate them first.");
}
if (string.IsNullOrEmpty(this.localTileCachePath))
{
throw new Exception("Local tiles do not yet exist. Please generate them first.");
}
4. Create a new ArcGISLocalTiledLayer. Pass the path to the local cache in the constructor.
// create a local tiled layer
var basemapLayer = new ArcGISLocalTiledLayer(this.localTileCachePath);
A local runtime geodatabase can be accessed using the static OpenAsync method on the Geodatabase class. Once
opened, you can access the tables inside. A geodatabase table that has geometry can be added to the map and displayed
with a FeatureLayer.
5. Open the local geodatabase and get a reference to the first table (it should contain only the marine wildlife sightings table).
Create a new FeatureLayer to display the table.
// open the local geodatabase, get the first (only) table, create a FeatureLayer to display it
var localGdb = await Geodatabase.OpenAsync(this.localGeodatabasePath);
var gdbTable = localGdb.FeatureTables.FirstOrDefault();
var operationalLayer = new FeatureLayer(gdbTable);
// give the feature layer an ID so it can be found later
operationalLayer.ID = "Sightings";
6. Initialize the local layers and await completion. If either layer was not initialized successfully, throw an exception with a
message for the user.
await basemapLayer.InitializeAsync();
await operationalLayer.InitializeAsync();
// see if there was an exception when initializing the layers
if (basemapLayer.InitializationException != null ||
operationalLayer.InitializationException != null)
{
// unable to load one or more of the layers, throw an exception
throw new Exception("Could not initialize local layers");
}
Add code to call the functions to load online (TryLoadOnlineLayers) or local data (TryLoadLocalLayers) when the
corresponding radio buttons in the UI are clicked.
8. Navigate to the DataOptionChecked function in your code behind. This is the event handler for the local and online radio
buttons.
9. Before calling code to load layers, clear all current layers in the map.
private void DataOptionChecked(object sender, RoutedEventArgs e)
{
MyMapView.Map.Layers.Clear();
10. Use a branching statement to load either online or local layers depending on what the user selected.
if (UseOnlineDataOption.IsChecked == true)
{
TryLoadOnlineLayers();
}
else // offline
{
TryLoadLocalLayers();
}
11. Test your code: run the app, zoom into an area of interest, generate local features and tiles, then toggle between online and
local data for the map.
As you zoom out of the map when using your local data, you'll notice that the map tiles and features only exist within the original extent at
which they were generated.
You've completed the tutorial, nice work. You now have a better understanding of how to generate local datasets from online services and
how to display them in your map. For more information about editing with offline feature data and synchronizing edits with the original
service, see the Editing, Edit features, and Sync offline edits topics.
Prerequisites
This tutorial requires a supported version of Microsoft Visual Studio and ArcGIS Runtime SDK for .NET. Refer to the appropriate topics in
the guide for information on installing the SDK and system requirements.
Familiarity with Visual Studio, XAML, and C# is recommended.
Tip: ArcGIS Runtime SDK for .NET provides a project template for creating your mapping app, called
ArcGIS Runtime 10.2.7 for .NET App. Creating your project from the template will add the
appropriate references and a page with a map view containing a single base layer. In this tutorial,
you'll build your app from a blank template.
4. Choose a folder location for your new project and name it MvvmApp.
6. Right-click the References node under the MvvmApp project listing in the Visual Studio Solution Explorer window, and click
Add Reference in the context menu.
7. Check the listing for the ArcGIS Runtime for Windows Store apps assembly under Windows 8.1 > Extensions.
Note: In order for your app to build, you need to specify a build target for the project. The default value of
Any CPU will not work and is why the new references are shown with a yellow warning icon.
You will now specify a build platform for the app.
9. Choose BUILD > Configuration Manager.
10. Choose x86 in the Active solution platform drop-down menu. This will target a 32-bit platform for the app.
Add a map
Now that you've created your project and added a reference to ArcGIS Runtime, you're ready to add a map to your app. In your map,
you'll display a satellite imagery basemap from a public map service provided by ArcGIS Online and a point layer showing (fictional)
community submitted incident reports. You'll define a custom renderer for the points and set an initial extent centered on Europe.
Steps:
To use the ArcGIS Runtime in the XAML designer, make references to required XML namespaces.
1. Open the MainPage.xaml file in the Visual Studio designer.
2. Go to the XAML view of the designer, and add the following XML namespace references to the Page XAML element. Visual
Studio offers IntelliSense to help complete the URL portion of the statement.
xmlns:esri="using:Esri.ArcGISRuntime.Controls"
xmlns:layers="using:Esri.ArcGISRuntime.Layers"
xmlns:data="using:Esri.ArcGISRuntime.Data"
xmlns:sym="using:Esri.ArcGISRuntime.Symbology"
3. Add the following XAML inside the <Grid> element to define a new MapView control on the page containing a Map control
with a few layers.
<esri:MapView x:Name="MyMapView">
<esri:Map>
<esri:Map.InitialViewpoint>
<esri:ViewpointExtent XMin="-1631122.453"
YMin="4253523.549"
XMax="4163264.136"
YMax="8976345.495" />
</esri:Map.InitialViewpoint>
<layers:ArcGISTiledMapServiceLayer ID="BaseMap"
ServiceUri="http://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer"/>
<layers:FeatureLayer ID="Incidents">
<data:ServiceFeatureTable
ServiceUri="http://sampleserver6.arcgisonline.com/arcgis/rest/services/SF311/FeatureServer/0"/>
<layers:FeatureLayer.Renderer>
<sym:SimpleRenderer>
<sym:SimpleMarkerSymbol Color="Red" Size="16" Style="Triangle"/>
</sym:SimpleRenderer>
</layers:FeatureLayer.Renderer>
</layers:FeatureLayer>
<layers:GraphicsLayer ID="PointGraphics"/>
</esri:Map>
</esri:MapView>
4. Run your app. A map similar to the one shown below appears.
Note: The Incidents layer is based on an editable feature service. The number and location of
features (red triangles) can vary day to day. If features (red triangles) don't appear in your initial
map extent, try zooming to another location.
Steps:
1. In your MainPage.xaml file, select the entire contents of the MapView control (but not the map view itself). Choose Cut
from the Edit menu to remove this XAML from its containing MapView.
Your page should now contain an empty MapView, as shown in the following example:
<Grid>
<esri:MapView x:Name="MyMapView">
</esri:MapView>
</Grid>
</Application.Resources>
4. Place your mouse cursor inside the Application.Resources element in the page, and choose Paste from the Edit
menu.
The XAML that defines your map is added to the application's resource dictionary as shown in the example below.
<Application.Resources>
<esri:Map>
<esri:Map.InitialViewpoint>
<esri:ViewpointExtent XMin="-1631122.453"
YMin="4253523.549"
XMax="4163264.136"
YMax="8976345.495" />
</esri:Map.InitialViewpoint>
<layers:ArcGISTiledMapServiceLayer ID="BaseMap"
ServiceUri="http://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer"/>
<layers:FeatureLayer ID="Incidents">
<data:ServiceFeatureTable
ServiceUri="http://sampleserver6.arcgisonline.com/arcgis/rest/services/SF311/FeatureServer/0"/>
<layers:FeatureLayer.Renderer>
<sym:SimpleRenderer>
<sym:SimpleMarkerSymbol Color="Red" Size="16" Style="Triangle"/>
</sym:SimpleRenderer>
</layers:FeatureLayer.Renderer>
</layers:FeatureLayer>
<layers:GraphicsLayer ID="PointGraphics"/>
</esri:Map>
</Application.Resources>
You now have several warnings displayed in your Visual Studio designer. You will add required XML namespace references
and provide a value for the x:Key property to fix them.
5. Add the same XML namespace references you added earlier to the Application element of the App.xaml page, as
shown in bold in the following example.
xmlns:esri="using:Esri.ArcGISRuntime.Controls"
xmlns:layers="using:Esri.ArcGISRuntime.Layers"
xmlns:data="using:Esri.ArcGISRuntime.Data"
xmlns:geometry="using:Esri.ArcGISRuntime.Geometry"
xmlns:sym="using:Esri.ArcGISRuntime.Symbology"
6. Add an x:Key property to the Map element and give it a value of IncidentMap.
<esri:Map x:Key="IncidentMap">
Note: The x:Key property is used to identify a resource and should be unique within the scope of the
object (in this case, the entire application).
7. Return to the XAML for your Page and add XAML to bind the IncidentMap resource to the MapView element, as shown
below.
<esri:MapView x:Name="MyMapView" Map="{Binding Source={StaticResource IncidentMap}}">
</esri:MapView>
A data binding for the Map property is specified using the binding markup extension in XAML. Bindings can be made to
resources in the application, other elements on the page, or to a class in the app that provides data. More information about
data binding in a XAML app can be found at Data binding overview (MSDN).
8. Run your app. The map displays as it did when it was defined directly in the MapView.
Is your app implementing the MVVM pattern? Not in its purest form, but the App.xaml page is acting as a view model by providing a Map
to which the MapView can bind. This illustrates one of the benefits of using the pattern, which is clearly separating the UI from
implementation details where possible. The MapView is a UI control, which belongs on the page. The Map and the layers it contains are
data displayed in the control, which is subject to change and should be managed outside the UI. With this architecture, the page and the
map are loosely coupled, which means you can easily make changes to one without affecting the other. To change the map displayed in
the page, for example, you could point the binding to another resource available in your application.
To implement the more traditional form of the MVVM pattern, you will create a view model class. The class acts as the data context for the
page, and exposes data and functionality to which the UI can bind.
several different views in your app. You will create a single view model (MapViewModel) to provide all data and functionality needed by
your view.
Steps:
1. Right-click the MvvmApp node in the Solution Explorer and choose Add > Class from the context menu to add a new
class to your project. Name the class MapViewModel.cs.
2. At the top of the MapViewModel code module, add the following using statements.
using Esri.ArcGISRuntime.Controls;
using Esri.ArcGISRuntime.Layers;
The Esri.ArcGISRuntime.Controls namespace contains the Map class. You will use classes from the
Esri.ArcGISRuntime.Layers namespace later.
3. Add a new property to the class called IncidentMap, as shown in the following example.
private Map map;
public Map IncidentMap
{
get { return this.map; }
set { this.map = value; }
}
The IncidentMap property provides a Map to which the view can bind.
4. Add a constructor to the MapViewModel class that initializes the map, as shown in the following example. You could build
the map programmatically by creating all of the required layers, symbolizing them, and setting the initial extent, and so on.
Instead, reference the Map that you defined earlier in the App.xaml resources.
public MapViewModel()
{
// when the view model initializes, read the map from the App.xaml resources
this.map = App.Current.Resources["IncidentMap"] as Map;
}
The map property of your view model is complete. Next, you will update the data binding to display the map on the page.
Note: If you want to set the view's data context programmatically, you can add the following two lines of code to
the constructor in your code behind for (MainPage.xaml.cs). If you add this code, proceed to step 4 to
update the data binding for the map.
this.DataContext = new MapViewModel();
Steps:
1. Open your App.xaml page. At the top of the page, inside the Application element, add an XML namespace reference
for the local assembly (MvvmApp), as shown in the following example.
<Application
x:Class="MvvmApp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:esri="using:Esri.ArcGISRuntime.Controls"
xmlns:layers="using:Esri.ArcGISRuntime.Layers"
xmlns:data="using:Esri.ArcGISRuntime.Data"
xmlns:geometry="using:Esri.ArcGISRuntime.Geometry"
xmlns:sym="using:Esri.ArcGISRuntime.Symbology"
xmlns:local="using:MvvmApp">
You need to define this namespace to access the MapViewModel class in your XAML.
2. Inside the Application.Resources element (below where the IncidentMap is defined), add XAML to define a new
MapViewModel object (from the local namespace) with the key MapVM.
<local:MapViewModel x:Key="MapVM"/>
This object serves as the data context for the main page. You can refer to it using its key, MapVM. By defining it in the App,
you can be assured that the object is created before any of the pages that use it as their data context.
3. Open the MainPage.xaml page. Set the data context for the entire page to the MapVM object, as shown in bold in the
following example.
<Page
x:Class="MvvmApp.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MvvmApp"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:esri="using:Esri.ArcGISRuntime.Controls"
xmlns:layers="using:Esri.ArcGISRuntime.Layers"
xmlns:data="using:Esri.ArcGISRuntime.Data"
xmlns:geometry="using:Esri.ArcGISRuntime.Geometry"
xmlns:sym="using:Esri.ArcGISRuntime.Symbology"
DataContext="{Binding Source={StaticResource MapVM}}">
Since the view model is set as the data context for the entire page, any control on the page can bind to properties exposed
by the view model class. You will bind the IncidentMap property to the Map property of the MapView control.
4. Change the binding statement for the MapView to point to the IncidentMap property. Because the page's data context is
set to a MapViewModel instance, it's implied that the binding comes from one of the properties of that object.
<esri:MapView x:Name="MyMapView" Map="{Binding IncidentMap}">
</esri:MapView>
5. Run your code. Again, the map should appear as it did when it was defined directly on the page.
What is the advantage of using such a scheme to display a map? The app looks the same regardless of where you define the map, yet
using a view model seems to add a lot of complexity. For a basic app like this, there really is no advantage to using the MVVM pattern. As
your app becomes more complex, however, you'll find that using an MVVM architecture makes your app much easier to maintain and
promotes sharing of code between apps.
Implement a command
Some controls, such as Button, CheckBox, RadioButton, and MenuItem provide a Command property. Commands are custom
classes that implement the ICommand interface and define what happens when a control is clicked (Execute method), and determine
when it should be enabled (CanExecute method). Commands can be created in your view model, and bound to the Command property
of the appropriate control.
Tip: There are several MVVM frameworks available that provide an implementation for ICommand. When using
these frameworks, you can instantiate command objects in your view model without the intermediate step
of creating your own command class, as described in this section. If you plan to use MVVM extensively,
consider using a framework when developing your apps, such as MVVM Light.
Steps:
1. Add a new class to your project. Name it DelegateCommand.cs.
2. The ICommand interface is in the System.Windows.Input namespace. Add a using statement at the top of the class
for this namespace.
using System.Windows.Input;
3. Implement the System.Windows.Input.ICommand interface in your class. The complete implementation for the class
is provided in the following example for you to paste into your class.
class DelegateCommand : System.Windows.Input.ICommand
{
// a var to store the command's execute logic (button click, for example)
private readonly Action<object> execute;
// a var to store the command's logic for enabling/disabling
private readonly Func<object, bool> canExecute;
// constructor: store the logic for executing and enabling the command
public DelegateCommand(Action<object> executeAction, Func<object, bool> canExecuteFunc = null)
{
this.canExecute = canExecuteFunc;
this.execute = executeAction;
}
// if it was passed in, execute the enabling logic for the command
public bool CanExecute(object parameter)
{
if (this.canExecute == null) { return true; }
return this.canExecute(parameter);
}
When you need to bind a button to a command, create an instance of your DelegateCommand and pass in the behavior
for the command execution and for enabling the control to the constructor. The parameter for the execute action is of type
object to give maximum flexibility to the command.
4. Save and close DelegateCommand.cs, since you no longer need to work in this class.
Steps:
1. Open your MapViewModel class. Define a public property called ToggleLayerCommand that returns a
DelegateCommand object, as shown in the following example.
public DelegateCommand ToggleLayerCommand { get; set; }
2. Create a new function to handle command execution, called ToggleLayer. This function toggles the visibility of a layer in
the map. The input parameter specifies the name of the layer to toggle.
private void ToggleLayer(object parameter)
{
var lyr = this.map.Layers[parameter.ToString()];
lyr.IsVisible = !(lyr.IsVisible);
}
3. Create another new function to determine the CanExecute state of the command. Since the command toggles a specific
layer, it should only execute (be enabled, in other words) if that layer exists in the current map. The same parameter, the
layer's name, is passed to this function.
private bool OkToExecute(object parameter)
{
var lyr = this.map.Layers[parameter.ToString()] as FeatureLayer;
return (lyr != null);
}
If a feature layer with the specified name does not exist in the map, OkToExecute returns false, which disables the
associated control.
4. In the MapViewModel constructor, add the following line of code to instantiate the ToggleLayerCommand. Pass in
theToggleLayer function as the command's execution logic and OkToExecute as the enabling logic.
public MapViewModel()
{
// when the view model initializes, read the map from the App.xaml resources
this.map = MvvmApp.App.Current.Resources["IncidentMap"] as Map;
ToggleLayerCommand = new DelegateCommand(ToggleLayer, OkToExecute);
}
Note: The CanExecute parameter for the DelegateCommand constructor was defined as optional.
You don't need to provide a value if you want the command to always be enabled.
Steps:
1. Add a new button to your MainPage.xaml page below the existing XAML for the MapView control.
<Button Height="50" Width="100"
HorizontalAlignment="Left" VerticalAlignment="Center"
Content="Toggle" />
2. Set the new button's Command property by binding it to the ToggleLayerCommand property of the view model.
<Button Height="50" Width="100"
HorizontalAlignment="Left" VerticalAlignment="Center"
Content="Toggle"
Command="{Binding ToggleLayerCommand}" />
3. Provide the incident layer's name as the command parameter by setting a value for the button's CommandParameter
property.
<Button Height="50" Width="100"
HorizontalAlignment="Left" VerticalAlignment="Center"
Content="Toggle"
Command="{Binding ToggleLayerCommand}"
CommandParameter="Incidents" />
4. Run your app. Click the Toggle button to verify that the code in the view model executes to turn the incidents layer on and
off.
Commands work well for binding functionality in your view model to certain controls in your view, such as buttons and menu choices.
But what if you need to handle other events, such as a selection change in a combo box, or mouse and touch events on the map view?
If you're interested in binding other event handlers from your view model, continue to the following section.
Steps:
1. Choose Project > Add Reference. In the Reference Manager dialog box, on the Extensions tab, check the listing for
Behaviors SDK (XAML). You'll find it under Windows 8.1 > Extensions.
After updating the project references, you must add an XML namespace reference to your MainPage.xaml page so those
classes can be used in your XAML.
2. Inside your page's Page element, add the XML namespace reference shown in the following example.
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:action="using:Microsoft.Xaml.Interactions.Core"
3. Add the following XAML inside the MapView element to define an EventTriggerBehavior for the map view's
ExtentChanged event.
<esri:MapView x:Name="MyMapView" Map="{Binding IncidentMap}">
<interactivity:Interaction.Behaviors>
<action:EventTriggerBehavior EventName="ExtentChanged">
</action:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
</esri:MapView>
You can respond to the EventTriggerBehavior using a function (method) or with a Command object. Because you need
a parameter (the MapView), use a Command and provide a CommandParameter to pass the current map view to the view
model code.
4. Add the XAML in the following example to define an InvokeCommandAction in response to the event. The
ExtentChangedCommand command does not yet exist in your view model; however, you will create it soon.
<action:InvokeCommandAction
Command="{Binding ExtentChangedCommand}"
CommandParameter="{Binding ElementName=MyMapView}"/>
The binding syntax shown in the previous code provides an example of binding to a XAML element. The command
parameter is being set with an element on the page called MyMapView, which is your map view control. The map view object
is needed to read current extent values.
Next, you will create the ExtentChangedCommand to handle the event.
5. Open MapViewModel.cs and add the following code to define a new DelegateCommand object called
ExtentChangedCommand.
public DelegateCommand ExtentChangedCommand { get; set; }
6. Create the function shown in the following example to respond to an extent change. For now, verify that you can get the
extent object from the map view.
public void MyMapViewExtentChanged(object parameter)
{
var mv = parameter as MapView;
var extent = mv.Extent;
7. In the constructor for MapViewModel, add the code shown in the following example to create the
ExtentChangedCommand.
public MapViewModel()
{
// when the view model initializes, read the map from the App.xaml resources
this.map = MvvmApp.App.Current.Resources["IncidentMap"] as Map;
ToggleLayerCommand = new DelegateCommand(ToggleLayer, OkToExecute);
ExtentChangedCommand = new DelegateCommand(MyMapViewExtentChanged);
}
The CanExecute logic for DelegateCommand is optional, which is why you didn't need to specify it.
8. Set a breakpoint on the last line of the MyMapViewExtentChanged function and run your app. You hit the breakpoint as
soon as the app starts.
The binding successfully handles the extent changed event in the view model. The process described here could be used to handle any
event raised by UI controls, including those that don't provide a Command property.
More work is required to show the extent values in the UI. If you're interested in completing this functionality, proceed to the next section.
Steps:
1. Open MapViewModel.cs and add the following code to define a CurrentExtentString property.
private string extentString;
public string CurrentExtentString
{
get
{
return this.extentString;
}
set
{
this.extentString = value;
}
}
2. Add the following code to set the value of CurrentExtentString in the extent changed event handler.
public void MyMapViewExtentChanged(object parameter)
{
var mv = parameter as MapView;
var extent = mv.Extent;
CurrentExtentString = string.Format("XMin={0:F2} YMin={1:F2} XMax={2:F2} YMax={3:F2}",
extent.XMin, extent.YMin, extent.XMax, extent.YMax);
}
Extent coordinates are formatted in a string that looks like this: XMin=-2598746.47 YMin=4253523.55
XMax=5130888.16 YMax=8976345.50.
3. Open your view, MainPage.xaml, and add the following XAML to define a new TextBlock to display the extent string.
Place this XAML below the XAML that defines your map view.
<TextBlock Height="30" Width="Auto"
FontSize="16" Foreground="AliceBlue"
HorizontalAlignment="Center" VerticalAlignment="Bottom"
Text="{Binding CurrentExtentString}"/>
The text block appears along the bottom center of the application and is bound to the property containing the extent values.
4. Run your app. The extent string does not appear as expected.
For data binding to work as expected, you must raise a notification event when bound properties change. In this case, the
extent string is being bound to the text block before it is given a value (it contains an empty string). When the value updates
in the extent changed handler, the view is never notified that it should get an updated value. If you provided a default value
for CurrentExtentString, you would see that value display when the app starts, but the value would not change.
If that's the case, why does the binding for the map work? The IncidentMap property of the view model is set in the class
constructor, which executes before the view model is set as the page's data context.
To raise the required notification when a property changes, you must implement the INotifyPropertyChanged interface
in the System.ComponentModel namespace.
5. Add the following using statements to the top of your MapViewModel class
using System.ComponentModel;
using System.Runtime.CompilerServices;
8. Raise the change notification in your CurrentExtentString property's setter by calling the
RaiseNotifyPropertyChanged function.
9. Run your app again. The extent information appears at the bottom of the map. Zoom and pan the display to see the
information update.
You've completed the tutorial, nice work. You now have an understanding of how to construct an app using the MVVM design pattern,
including: data binding, commands, event triggers, and property change notification. To appreciate the usefulness of the MVVM pattern,
create a new project (perhaps for another .NET platform) and reuse your ViewModel and Command classes for a different UI (View).
To learn more about these topics, consult the following resources:
Data binding overview (MSDN)
MVVM pattern made simple (CodeProject)
MVVM Commands (MSDN)
INotifyPropertyChanged (.Net Documentation)
MVVM Light toolkit (CodePlex)
Caliburn.Micro framework (GitHub)
Related Topics
Determine your app/map pattern
Provide map tools
Native vs. web
Layer types
Layers can generally be thought of as basemaps, operational, or graphics layers, depending on the data they display and how they are
used, with each type of layer offering different functionality and performance characteristics.
Background data that provides context and does not change often is generally considered as the basemap, for example,
topography, imagery, streets, or buildings data. Basemap data is generally prepared and cached on a server as ready-to-access
image tiles that are efficient to request and display in an app. ArcGIS Online provides a free set of ready-to-use basemap layers
that are pre-rendered and cached to ensure they draw quickly. Alternatively, you can use the ArcGIS platform to create your own
basemaps. For details on functionality and performance, see Basemap layers in the Layer types topic. For details on using offline
basemaps, see Create an offline map.
Data edited by app users, periodically changing data, or data resulting from analyses, may best be considered as operational
layers. Typically, operational data is created and maintained by your organization. Displaying or working with operational data is
often the main focus of an app. For details on functionality and performance and how to take operational layers offline, see
Operational layers in the Layer types topic.
Live, rapidly changing, ephemeral data may be appropriate for a graphics layer. For example, vehicle or workforce locations,
geotriggered events, or temporary query results. Graphics are generated in memory in an app, or created in an app based on an
external information feed. For details on functionality and performance, see Graphics layers in the Layer types topic.
Other types of specialized layers provide the ability to add a wide range of data and services to a map, for example WMS services and
OpenStreetMap.
A wide variety of layer classes are provided by the API. Each can be used to display a specific data type, and each has its own
functionality and performance characteristics. Generally, each layer class is used for basemap, operational, or graphics layers. However,
these are not absolute rules, and the choice of class should be based on an understanding of the characteristics of each type. For
information on the functionality and performance of different types of layers, see Layer Types.
Layer order
The layer order in a map is important. Basemaps typically cover the entire surface of the map. They are added to the map first so that they
draw under the layer and do not obscure other layers. Layers can be re-ordered, but this will not change the map's spatial reference.
Add operational layers to the map next. Graphics layers are typically added last and show on top of all other layers.
Spatial reference
Maps and layers use spatial references to help define where coordinates are located on the earth's surface. Distance units and
coordinates of map operations are determined by the spatial reference of the map. The first layer in a map, typically the basemap, defines
the spatial reference of the map, and this cannot be changed.
If the spatial reference of layers in a map are different to the spatial reference of the map, the layers must be reprojected to the spatial
reference of the map before displaying. Some layer types cannot be re-projected, for example, tiled map layer services draw and cache on
a server, and cannot be changed on the client.
To maximize performance, avoid reprojection entirely by ensuring all layers have the same spatial reference as the map.
change the map online independent of your application code, reducing the need for application redeployment. It is also easier to offer the
user a choice of pre-defined online maps to open using the Portal API. Note that online maps may only contain online data.
Alternatively, you can build a map by defining and adding layers at runtime programmatically, or even add code to allow your users to add
their layers. You can also make temporary changes to a map that you created online, by adding or removing layers, and changing a
layer's appearance. This approach enables you to add offline layers to your map, and offers the flexibility of programmatic control, but
lacks the centralized maintainable map.
It is not possible to directly load map package (MPK) files or map documents saved from ArcGIS for Desktop into the map.
Behavior at runtime
Also consider how the map draws and behaves at runtime, and how the user interacts with it.
Wraparound maps
Most flat representations of the world only extend to 180 degrees east and west longitude, the approximate location of the international
date line, making it more difficult to visualize routes or shapes that cross the pacific ocean. However, the map can be configured to
display the eastern and western hemispheres wrapping around each other and forming a continuous surface, giving the impression that
the map is endless. Panning a map becomes similar to spinning a globe.
Temporal data
Geographic data can change over time; therefore, some layers may show stored temporal data, which is information about the changing
state of a dataset over time. For example, the progression of a hurricane changes in sea temperature, destruction of wildlife habitat, or
the spread of disease. These layers are called time-aware layers.
You can configure a map with time-aware layers to display different periods of time. Stepping through time in your map can help you
easily identify trends and patterns in the data that may have otherwise remained unnoticed. See the temporal renderer section of the
Symbols and renderers topic for information about displaying temporal data on the map.
Related Topics
Layer Types
Use a MapView to display a map
Add layers with code
Layer Types
Different layer types are used to draw different data types. Generally, the layers in a map can be categorized as either basemap,
operational, or graphics layers. The functionality and performance may differ, depending on the characteristics of the data and how it is
accessed and displayed in an app.
See Maps and layers to learn more about choosing how to build maps from layers.
Basemap layers
Basemap data is typically provisioned as a tiled map layer. Different classes are used to create basemap layers, depending on the
displayed data.
If your basemap must be used in maps with a wide variety of different spatial references, or changes frequently, or is used infrequently, it
may be more appropriate to publish data as a dynamic map service. Additionally, if your operational data changes infrequently and is used
by a large amount of users, it may be more appropriate to publish it as a tiled map service.
Functional characteristics
Because each tile image already exists on the server, it is not possible to change the visibility of the individual layers or the service's
default spatial reference of the map (they can be considered as static map services). In addition, the data cannot change over time
unless the cache is refreshed. Tiled service layers cannot be queried.
Performance characteristics
Tiled map services are some of the fastest map services available in the runtime. Map images are pre-created and cached by the
server, and returned from the server very quickly. Multiple images are usually returned for a single map extent. Requests are made on
multiple threads and the responses are handled asynchronously (tiles are requested and drawn individually from one another). This
approach results in many small requests to the server and little client-side processing to draw the returned images. The size of each
returned image increases as the resolution or complexity of the images increase. For example, high-resolution imagery tiles are larger
in file size than topographic mapping for the same area and map extent.
Local tiled layers display even faster than tiled service layers, as no network calls are required to retrieve the image tiles. However,
data must be prepared in advance by being generated and downloaded to the device over the network, or by provisioning the
generated files directly to the device file storage. Other functional and performance characteristics are similar to that of tiled service
layers.
Operational layers
Operational data is typically provisioned as a feature service, or as a dynamic map service. The choice of service type depends on what
functionality and performance characteristics are required for the layers. If editing is required, use feature services; however, if complex
rendering is required, dynamic map services may be more appropriate. More differences are highlighted below.
If your operational data does not require editing, changes infrequently, and is used by a very large amount of users, it may be more
appropriate to publish it as a tiled map service. Conversely, if you have a basemap that must be used in maps with a wide variety of
different spatial references, or changes frequently, or is used infrequently, it may be more appropriate to publish data as a dynamic map
service.
Feature layers
Feature layers display data from feature services. Feature layers can be used to display, select, and query features in a layer. Use
feature layers to edit geometry, attributes, and attachments, if the underlying feature service supports editing.
Features can be retrieved from the server as the app is used, or alternatively downloaded when the device is connected, and cached
locally for use when the device is offline. Choosing the most appropriate API option enables your app to provide the workflows required,
and allows it to adapt to the requirements of the situation. See the sections below for more information on the different options available.
Online
API classes: ServiceFeatureTable, FeatureLayerThe geometry, attributes, and attachments of features from a feature
service are temporarily cached in a table on the client. The feature layer uses this table to draw the features natively in the map,
based on the map extent. New features are retrieved automatically when you navigate the map. Changes to features already cached
in the app are not retrieved from the server table unless the layer is specifically refreshed. The local table cache is discarded when
the layer is disposed.
Create and initialize a ServiceFeatureTable, then create a FeatureLayer by passing in the ServiceFeatureTable to the
constructor, and add the FeatureLayer to the map. The ServiceFeatureTable class is a subtype of ArcGISFeatureTable,
which is an abstract base class for online and offline feature tables.
Offline
API classes: GeodatabaseFeatureTable, FeatureLayerA local cache of a feature service can be downloaded from ArcGIS
for Server and displayed as a layer in your app, without the need to remain connected to the service. Features are downloaded to a
local geodatabase file, using the GeodatabaseSyncTask.
Create and initialize a GeodatabaseFeatureTable, and create a FeatureLayer by passing in the GeodatabaseFeatureTable
to the constructor, then add the FeatureLayer to the map. Learn more about creating offline maps.
Functional characteristics
As the feature attribute, geometry, and attachment information is cached locally, individual features in these layers can be queried
and filtered based on spatial queries or text-based WHERE clauses. If the layer is created from an editable ArcGIS for Server feature
service, the feature layer can be edited, and edits pushed to the service when required.
If the feature service the layer was originally created from supports syncing, edits made to the features in an offline layer can be
uploaded to the service, and updates from the service can be synced to the client app.
Performance characteristics
As full feature information is cached locally, and features are drawn natively, this layer type offers excellent performance of display
when zooming and panning the map, within the extent of cached features. Querying such features is also efficient, enabling app
functions such as providing real-time updates of query results in a map. This performance comes at a slight cost of initial display
speed when the layer is first created from the service, as the local feature cache must be built. Additionally, app memory increases
with the number and complexity of the features cached.
Offline feature layers may display faster than online feature service layers, as no network calls are required to retrieve the feature
information. Additionally, querying and filtering is equally efficient. The cache must be initially created, which requires server-side
processing time, and the download to the device may require extensive network usage and subsequent local device storage. Network
usage can be eliminated by provisioning the cache directly to the device in advance, by creating the cache using a desktop computer
and copying it to the device internal memory (or expandable memory cards if your device supports this).
Functional characteristics
Since map images are drawn by the server on every request, if your data changes, those changes are seen as soon as a new map
image is requested. In addition, the visibility of individual map layers can be changed, and the data shown can be filtered by adding
individual layer definition expressions. The spatial reference of this layer type can be changed from the service's default, and ArcGIS
for Server re-projects each image on-the-fly to the requested output spatial reference (that of the map).
The API does not include specific methods to query individual dynamic map service layers. However, the layer's end point URL can
be used by a find task, identify task, query task, or used to create a separate queryable feature layer.
Performance characteristics
For every map request, ArcGIS for Server creates a map image on-the-fly. Consequently, the server rendering time depends on the
amount and complexity of the data in the map. However, if the map service is well optimized, this should result in a relatively quick
response to the client, but will typically be longer than responses for an equivalent tiled map service layer. The file size of the returned
map image also depends on the data in the map. As the server response is an image, this can be drawn quickly as it requires little
client-side processing.
Dynamic map service layers are good candidates for showing features that change periodically over time, or that require some sort of
filtering by the user, as long as the feature information (attributes, geometry, or symbol) is not required in the client. They are often
used in conjunction with a feature layer in selection mode to show the latest map data without having to pull all of the feature
information from the server (as with feature layers) on every map request.
Graphics layers
API classes: GraphicsLayerGraphics layers can be used to display information that is not covered by the other types of layer
above. Graphics are defined in memory in your app, based on user actions, resulting from an operation, or converted from the
information in an external information feed. Graphics in a graphics layer can contain geometry and attribute information, and can draw
graphics using individual symbols or a layer-based renderer. Like features in a feature layer, each graphic draws natively in the map.
Feature layers share a little functionality with graphics layers. For more information about when to use feature layers versus graphics
layers, see Features and graphics.
Functional characteristics
As a graphic contains geometry and attribute information, you can display information about the graphics. For example, you can show
pop-ups for graphics in a graphics layer. You can also find graphics using screen coordinates HitTestAsync method, in repsonse to
user action events on the map. The graphics layer is responsible for drawing graphics on the map in spatial coordinates. It is not
designed for drawing non-geographical marginalia such as north arrows or copyright text.
Performance characteristics
It is not recommended to add too many graphics to the graphics layer, as they are held in the device memory. If you're working with a
lot of features (thousands), it may be more appropriate to put these into a feature layer, by creating a feature service.
Graphics layers are designed to best perform when graphics change location regularly, with optimal animation of the features upon
zooming in and out on the map. It is possible to change the default rendering mode of a graphics layer to instead be optimized to
draw greater numbers of features added to the layer in batches. Layers with the same rendering mode should be grouped together.
3D layers
In general, you work with layers in 3D (added to a Scene control, in other words) the same way you work with them in 2D (added to a
Map). All of the layer types that are supported for display in a Map can also be used in a Scene. Just like those included in a Map, layers
can be added to a Scene at design time using XAML or at runtime using code, and are drawn in the order in which they are added.
Elevation values for 3D visualization are applied to layers using an elevation source defined on the Scene control.
With the 10.3 release of ArcGIS for Server, scene services are now available for delivering 3D content. They support publishing and
consuming large volumes of multipatch features, such as buildings for entire cityscapes. Scene services are created by publishing a
scene using ArcGIS Pro. These services can be consumed in your ArcGIS Runtime app using a SceneLayer.
The GraphicsLayer and GraphicsOverlay classes provide a SceneProperties property to define behavior when rendering
graphics in a scene. The property is set with a LayerSceneProperties object that defines the SurfacePlacement setting to control
how graphics display relative to the scene's elevation source. When displaying in a map, SceneProperties for graphics are ignored.
Feature services may provide z-coordinate values for feature geometry, but these values are not used when displaying a feature layer in
a scene. As a workaround, query the feature service (with ReturnZ = true) and add the results to a graphics layer with the
appropriate surface placement. The following example queries a z-enabled feature service then displays the graphics in a scene.
// query for all graphics in the feature service, include z-coordinate values
var queryTask = new QueryTask(new Uri("http://myserver.com/arcgis/rest/services/FlightPaths/FeatureServer/0"));
var query = new Query("1=1");
query.ReturnZ = true;
var result = await queryTask.ExecuteAsync(query);
// create a graphics layer to show the graphics using absolute placement using the z values
var graphicsLayer = new GraphicsLayer();
graphicsLayer.SceneProperties.SurfacePlacement = SurfacePlacement.Absolute;
See the Add layers to your Scene topic for more information about working with layers in 3D.
Kml layers
Keyhole Markup Language (KML) is an XML format for describing geographic features for visualization in two dimensions (in a Map) or
three dimensions (in a Scene). A KML document defines a set of geographic features using coordinates of latitude, longitude, and
elevation. Rendering information describes how features are symbolized, and may reference local resources, such as image files.
Additional information can define a time component for the data or three dimensional visualization properties such as pitch, heading,
and elevation to describe a camera position.
A KML file can contain one or more network links, which simply point to another KML file. The referenced file can be updated and
maintained seperately, ensuring that the user sees the most current version of the data. Network links can be set to refresh their data
based on a time interval or when the user interacts with the display, making them especially useful for displaying dynamic data.
The following network link is included in the KML file at http://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/
1.0_week_age_link.kml and is used to display earthquakes from the USGS website. The data in the layer will be refreshed every 300
seconds (five minutes).
<NetworkLink>
<visibility>1</visibility>
<refreshVisibility>0</refreshVisibility>
<open>1</open>
<name>USGS Magnitude 1.0+ Earthquakes, Past Week</name>
<Snippet maxLines="1">Updates every 5 minutes</Snippet>
<Link>
<href>http://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/1.0_week_age.kml</href>
<refreshMode>onInterval</refreshMode>
<refreshInterval>300</refreshInterval>
</Link>
</NetworkLink>
KML files use a .kml extension for plain KML text files or .kmz for compressed files, which contain a KML file (called "doc.kml" by
convention) and optionally includes subfolders containing resources referenced by the file, such as images, icons, or 3D models used to
display the features. In your ArcGIS Runtime apps, you can use KmlLayer to read and display geographic information from a .kml or
.kmz file, either stored locally or accessed from an online source.
The following example adds a layer from a KML file hosted by the USGS showing recent earthquakes. This KML file contains the
network link shown in the previous example, and will cause the layer to update every five minutes.
// create a KML layer from an online file
var sourceUri = new Uri("http://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/1.0_week_age_link.kml");
var kmlLayer = new KmlLayer(sourceUri);
In 2008, KML became an international standard of the Open Geospatial Consortium (OGC). The specification for the current version,
which is 2.2, can be found on the OGC Website. The standard also provides a mechanism for extensions, which allows the addition of
elements beyond the scope of the standard. Google, for example, provides several extensions to the KML standard that are described
in the Google Developers KML Reference. If an extension is not supported by a client, it is silently ignored and the rest of the document
is loaded. This allows a new client to support additional functionality from an extension without breaking support for existing clients.
ArcGIS Runtime SDK for .NET is targeting support for KML version 2.2 and some extensions. The following lists some of the
functionality, either from the KML 2.2 specification or Google extensions, that you won't yet find in the ArcGIS Runtime KML
implementation.
Tour
NetworkLinkControl message
Specialized layers
Several specialized layer types are available to provide geographic information from a variety of formats, including Bing, Open Street Map,
and Web Map Service (WMS). The following layer classes are available to support the use of specialized types of data in a map.
WMSWeb Map Service layers allow you to add Open Geospatial Consortium (OGC) WMS services to a map. These services
are a type of dynamic map service, and may function as basemap or operational layers. The WmsLayer is used to add WMS
services to a map.
Bing mapsBing maps services can be added as layers in a map by using the specialist BingLayer class. These services are
tiled map services that usually provide basemap layers for a map.
OpenStreetMapOpen StreetMap services can be added as layers in a map by using the specialist OpenStreetMapLayer
class. These services are tiled map services that usually provide basemap layers for a map
Message groupsMessage group layers display graphics with military symbols from one of the supported symbol dictionary
types.
Group layersGroup layers are composed of a collection of other layers, and are used to represent datasets that are composed
of many different layers.
Related Topics
Add layers with code
Use a MapView to display a map
Note: Although the term can also refer to a graphic, "feature" is most often used to refer to things like geodatabase
or geopackage features, meaning features stored in a database. Graphics are usually called "graphics",
although "graphic feature" would be more precise.
Features...
Have geometry
Have attributes stored in a table
Are stored on disk
Are displayed through a feature layer (of a single geometry type)
Are symbolized according to the renderer defined for the feature service or the feature layer that contains them
Can be selected via the feature layer
Graphics...
Have geometry
Have attributes stored in a collection of key/value pairs
Are stored in memory
Are displayed through a graphics layer (that can display graphics of diverse geometry types)
Can be symbolized individually or according to the renderer applied to the graphics layer that contains them
Can be selected (the selection state is managed by the graphic)
Some display properties can be defined by the graphic, such as visibility and draw order
You can publish features as part of a feature service. Layers in a feature service can be displayed in a map, symbolized in various ways,
and queried using attribute, spatial, or temporal criteria. The rich editing tools available in the Runtime SDK also make it possible to
expose editing functionality in your application, including the ability to control the types of edits made and who gets to make them.
The following example adds a new feature layer to the map based on an online data source. The symbology (renderer) used to display the
layer is defined with the feature service.
// define the online data source (ServiceFeatureTable), get features in Web Mercator coordinates
var incidentsFeatureTable = await ServiceFeatureTable.OpenAsync
(new Uri("http://sampleserver6.arcgisonline.com/arcgis/rest/services/SF311/FeatureServer/0"),
sr_override: SpatialReferences.WebMercator);
// create a new feature layer, pass the data source to the constructor
var incidentsLayer = new Esri.ArcGISRuntime.Layers.FeatureLayer(incidentsFeatureTable);
// use the MapView's Editor to get polyline geometry from the user
var line = await MyMapView.Editor.RequestShapeAsync(Esri.ArcGISRuntime.Controls.DrawShape.Polyline,
lineSymbol, null);
Related Topics
Search for features
Edit features
Add graphics and text
Dynamic rendering
Dynamic rendering leverages the graphics processing unit (GPU) to render graphics. The amount of graphics processing that can be
handled is directly tied to the processing power and memory available for the GPU. Dynamic rendering is well suited for animation and
ensures that graphics are updated while navigation operations are running. As the user pans or zooms, for example, the graphics will
update their display immediately (without waiting for navigation to complete, in other words). Dynamic rendering provides a smoother
display experience for the user but can cause decreased performance when working with a large number of graphics.
Static rendering
Static rendering relies on the system central processing unit (CPU) and system memory rather than on GPU resources. Graphics that are
rendered in static mode are not immediately updated while the user pans or zooms the display. Instead, the graphics are updated only
after navigation is complete. This allows you to display a large number of graphics without a performance penalty during navigation but
produces a less polished graphic display.
Note: Static rendering of graphics can be CPU and memory intensive, which can impact device
battery life.
Alignment properties related to graphic display are ignored when the rendering mode of a graphics layer or overlay is set to static.
Symbols align with the map or scene view regardless of the value of AngleAlignment. If the view rotates, for example, the symbols will
follow the orientation of the view and not the screen regardless of the value of the MarkerSymbol.AngleAlignment property.
Rendering in 3D
Rendering in a scene (in three dimensions, in other words) has some unique challenges. Understanding how dynamic and static rendering
affect three-dimensional graphic display can help you decide which mode is most appropriate for particular graphics in your scene.
Dynamic rendering in three dimensions is especially resource-intensive and may degrade performance. Static rendering, on the other
hand, has limitations that affect three-dimensional display.
RelativeElevation of each graphic is calculated relative to the terrain elevation at the x,y location. This simply adds the
graphic's z-value to the elevation at the surface.
To display graphics using the Draped elevation mode, you can use either dynamic or static rendering. Only dynamic rendering,
however, supports Absolute or Relative mode. If graphics are rendered in static mode, they are always draped on the surface,
regardless of the value assigned to the elevation mode property. The following image shows two graphics layers with the elevation
mode set to absolute. Only the dynamic layer (red) supports this placement option and applies the z values for the graphics.
Updating graphics
If graphics are updated frequently, either by moving their geographic position (x, y, z coordinates) or changing symbol properties (color,
size, style, and so on), dynamic rendering is better suited to display them. For display in a scene, static rendering requires that graphics
are created for every level of detail. If graphics are updated, therefore, the scene tiles will be recreated at all levels and may cause the
display to flash as they are being generated.
Symbol size
When graphics are rendered in a scene in static mode, the size of the symbol is determined for each tile in the underlying base map.
The size of graphic symbols (line width, for example) is determined based on the level of detail for each tile. Symbol size for the same
graphic may vary, therefore, between tiles displayed in the scene. This may produce an inconsistent symbol across tile boundaries, as
shown in the following image:
Graphics are not updated frequently (do not change position or symbol, for example).
You don't need to display z-coordinate values (altitude, for example) for a set of graphics in a scene. When rendered in static
mode, graphics are draped on the scene surface regardless of the value you provide for surface placement.
Related Topics
Performance considerations
Add graphics and text
Symbols and renderers
Symbols
Remember that a symbol is not the thing being represented on the map. Instead, it controls how those things (graphics or features)
display. The relationship is similar, for example, between the words you are reading now (the content) and the font that is used to display
them (presentation). Changing the font style, size, and color will not change the meaning of the text, but is likely to have an impact on the
effectiveness of the presentation. Likewise, the quality of a map's presentation can improve with the proper use of symbols to convey
information.
Each symbol type is specific to a geometry type (point, line, or polygon). Whether you're applying a symbol directly to a graphic or using a
symbol to create a renderer, ensure the geometry type of the graphic or feature being symbolized is compatible with the symbol you want
to use. The following is a table of the symbols available in the API with the compatible geometry types and a brief description:
Depending on the type of geometry you want to symbolize, you will have different options available for defining your symbol. Points, lines,
and polygons all have a basic symbol you can use: SimpleMarkerSymbol, SimpleLineSymbol, and SimpleFillSymbol
respectively. You may also choose to symbolize points or polygons using the appropriate picture symbol: PictureMarkerSymbol or
PictureFillSymbol. Finally, a CompositeSymbol may be used to build more complex symbols for any type of geometry by layering a
group of symbols together.
Some symbols provide the ability to set an angle for rotating the symbol. This might be useful for showing things like direction (for wind
measurements or moving vehicles, for example). You may also have the ability to define an x or y offset, meaning the symbol displays at a
specified distance from the location of the feature it represents. This can be especially useful when working with text or with composite
symbols (described in a following section) where you may need to arrange several symbols to represent a feature.
Simple symbols
The simple symbol types (SimpleMarkerSymbol, SimpleLineSymbol, and SimpleFillSymbol) give you the ability to quickly
create a symbol by choosing a predefined style, setting a color, and defining a size (for markers) or width (for lines). For markers and
fills, you can also define an outline symbol (using a line symbol).
Symbols can be created using C# (in your code behind) or using XAML (in your UI markup). The example below illustrates creating
simple marker, line, and fill symbols using XAML. Notice that the outline for the fill symbol is specified using the line symbol that was
defined immediately above it.
<Grid>
<Grid.Resources>
<!--Define symbols in the Resources section (of a UIControl, Page, or App)-->
<symbols:SimpleMarkerSymbol x:Key="RedXSym" Color="Red" Style="X" Size="10"/>
<symbols:SimpleLineSymbol x:Key="DashedGreenLineSym" Color="Green" Style="Dash" Width="3"/>
<symbols:SimpleFillSymbol x:Key="BlueDiagonalHashFillSym" Color="Blue" Style="ForwardDiagonal" Outline="{StaticResource DashedGreenLineSym}"/>
</Grid.Resources>
<!-- ... -->
</Grid>
Picture symbols
Picture symbols, such as PictureMarkerSymbol and PictureFillSymbol, allow you to use an image to symbolize a feature. The
image may be stored locally, or come from an online source. The size of the image can be specified, and for picture fill symbols, will be
repeated (tiled) as necessary to fill the polygon it represents.
Picture marker symbols and picture fill symbols at version 10.2 or later can be created from an image on disk or from the URL to an
image on a remote public machine. Supported image formats for picture symbols are .PNG, .BMP and .JPG. Remote images are
downloaded once per application and cached for future use.
PictureFillSymbols are created from an image that's suitable for tiling. For example, an image of a tree can be used to create a
PictureFillSymbol so that a filled polygon looks like a forest when symbolized. As you zoom in, fewer trees display in the forest
since the map scale is getting closer to the image size. In a graphics layer, a minimum of four tiles are used to represent any one
polygon even at the most zoomed-in level.
Note: In a graphics layer in the default Dynamic rendering mode, images are not tiled neatly at each polygon
boundary, meaning the images look disjoint across boundaries. With a graphics layer set to the Static
rendering mode, images are tiled across the whole texture for a layer. Consequently, images are not
disjoint across polygon boundaries.
// define a picture fill symbol from a png file in the project's assets folder
var pictureSym = new Esri.ArcGISRuntime.Symbology.PictureFillSymbol();
await pictureSym.SetSourceAsync(new Uri("ms-appx:///Assets/JackAndJane.png"));
pictureSym.Height = 30.0;
pictureSym.Width = 30.0;
Composite symbols
A composite symbol is nothing more than a collection of other symbols applied in order (first to last) to produce a layering of symbols. A
composite symbol can be used to symbolize any type of geometry, as long as the proper symbol types exist in its collection (fill symbols
for polygons, for example).
At version 10.2 or later, composite symbols allow you to apply more than one symbol to a single geometry. For example, you can apply
both a SimpleMarkerSymbol and a TextSymbol to a point. A composite symbol contains a list of symbols, and symbols are drawn in
the order in which they appear in the list. A composite symbol has no significant properties of its own. This means, for example, to offset
a composite symbol relative to a geometry, the offset must be applied to each symbol in the list. A composite symbol can contain other
CompositeSymbols but cannot contain itself.
The following examples illustrate how various composite symbols would be applied to different geometry types.
SimpleMarkerSymbol, Point All symbols are applied to the point in order. If no offsets were applied to the individual symbols, the picture
PictureMarkerSymbol, marker may cover the simple marker beneath it (depending on the size of the symbols). By default, the text
TextSymbol symbol displays using the point as the lower left of the text string, and will likely overlap with the marker
symbols beneath.
SimpleMarkerSymbol, Point Only the SimpleMarkerSymbol can be applied to the point. While no exceptions are thrown, line and fill
SimpleLineSymbol, symbols will not be applied.
SimpleFillSymbol
PictureMarkerSymbol, Polyline All symbols are applied to the line, with the PictureMarkerSymbol applied to each of the line's vertices. Since
SimpleLineSymbol they are applied before the line symbol, the marker symbols appear under the line symbol.
TextSymbol, Polygon All symbols are applied to the polygon. Because they are applied in order, the simple fill will be covered by
SimpleLineSymbol, the picture fill (unless transparency has been set). The text symbol will be anchored at the center of the
SimpleFillSymbol, polygon's extent beneath both of the fill symbols.
PictureFillSymbol
The example below shows how to create a composite symbol that contains two simple marker symbols. The symbol added first (red
circle) displays below the symbol added last (blue triangle).
// Create a large red circle
var redCircleSym = new Esri.ArcGISRuntime.Symbology.SimpleMarkerSymbol();
redCircleSym.Color = Colors.Red;
redCircleSym.Style = Esri.ArcGISRuntime.Symbology.SimpleMarkerStyle.Circle;
redCircleSym.Size = 16;
graphicsLayer.Graphics.Add(pointGraphic);
Note: A symbol applied directly to the graphic overrides any symbols applied through the
layer's renderer.
Renderers
As the name implies, a renderer is an object that determines how features in a layer are drawn (rendered) on the display. A renderer is like
a collection of symbols that includes logic for applying the appropriate symbol to each feature in a layer. There are a variety of renderer
types, each designed to use a different rendering logic. Most renderers use attribute values to determine which symbol should be applied
to which features.
In a typical workflow, renderers are used to symbolize features in a feature layer, where the features will all be of the same geometry type.
It's up to you to create a renderer with symbols that can be applied to the geometry type of the layer (pursuant to the table above). A
renderer can also be applied to a graphics layer, but should not be used for a layer that has graphics of mixed geometry types. For such a
scenario, applying a symbol to each graphic as it's created is the preferred workflow.
There are several types of renderers you can create using the Runtime .NET API: including simple renderers, unique value renderers, and
class break renderers. Their class diagram is pictured here and each is described below.
Simple renderer
A simple renderer uses just one symbol such that all features are symbolized with the same symbol regardless of the feature's attribute
values.
The following example illustrates creating a simple renderer with XAML and applying it to a graphics layer in the map. Note that this
layer will not render geometry other than points (unless a symbol is explicitly defined for the graphic).
<Page
x:Class="SymbolsAndRenderers_Store.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:esri="using:Esri.ArcGISRuntime.Controls"
xmlns:layers="using:Esri.ArcGISRuntime.Layers"
xmlns:symbols="using:Esri.ArcGISRuntime.Symbology"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.Resources>
<!--Define a red "X" marker symbol-->
<symbols:SimpleMarkerSymbol x:Key="RedXSym" Color="Red" Style="X" Size="10"/>
<!--Define a simple renderer that uses the symbol above-->
<symbols:SimpleRenderer x:Key="MySimpleRenderer" Symbol="{StaticResource RedXSym}"/>
</Grid.Resources>
<esri:MapView x:Name="MyMapView">
<esri:Map x:Name="MyMap">
<layers:ArcGISTiledMapServiceLayer ID="BaseMap" ServiceUri="http://services.arcgisonline.com/arcgis/rest/services/World_Street_Map/mapserver"/>
<layers:GraphicsLayer ID="MyGraphicsLayer" Renderer="{StaticResource MySimpleRenderer}"/>
</esri:Map>
</esri:MapView>
</Grid>
</Page>
Caution: When applying a renderer that uses attribute values, such as unique value or class breaks renderers, you
must include the required fields in the layer's out fields. By default, only the object id and geometry fields
are returned for a feature layer.
The example below creates a unique value renderer that displays cities with different symbols according to the value of their state name
attribute. Since only California, Nevada, and Arizona have been defined explicitly in the renderer's UniqueValueInfoCollection,
features with any other value for the state name attribute (ST) display with the default symbol.
// create a symbol for each unique value
var californiaSym = new Esri.ArcGISRuntime.Symbology.SimpleMarkerSymbol { Color = Colors.Red, Size = 14, Style = Esri.ArcGISRuntime.Symbology.SimpleMarkerStyle.C
var arizonaSym = new Esri.ArcGISRuntime.Symbology.SimpleMarkerSymbol { Color = Colors.Blue, Size = 12, Style = Esri.ArcGISRuntime.Symbology.SimpleMarkerStyle.Dia
var nevadaSym = new Esri.ArcGISRuntime.Symbology.SimpleMarkerSymbol { Color = Colors.Green, Size = 14, Style = Esri.ArcGISRuntime.Symbology.SimpleMarkerStyle.Tri
// create a default symbol for values not defined in the renderer's unique value collection
var defaultSym = new Esri.ArcGISRuntime.Symbology.SimpleMarkerSymbol { Color = Colors.Gray, Size = 8, Style = Esri.ArcGISRuntime.Symbology.SimpleMarkerStyle.Circ
// create a UniqueValueInfo for each value; define the attribute value and associated symbol
var uniqueVal1 = new Esri.ArcGISRuntime.Symbology.UniqueValueInfo("CA", californiaSym);
var uniqueVal2 = new Esri.ArcGISRuntime.Symbology.UniqueValueInfo("AZ", arizonaSym);
var uniqueVal3 = new Esri.ArcGISRuntime.Symbology.UniqueValueInfo("NV", nevadaSym);
// create a unique value info collection; add the info for each unique value
var uniqueInfos = new Esri.ArcGISRuntime.Symbology.UniqueValueInfoCollection();
uniqueInfos.Add(uniqueVal1);
uniqueInfos.Add(uniqueVal2);
uniqueInfos.Add(uniqueVal3);
Note: If a default symbol is not defined for a unique value renderer, only features with attribute values defined in
the value collection display.
// create a symbol for each class of values (low, medium, and high)
var loSym = new Esri.ArcGISRuntime.Symbology.SimpleMarkerSymbol { Color = Colors.Red, Size = 4, Style = Esri.ArcGISRuntime.Symbology.SimpleMarkerStyle.Circle };
var medSym = new Esri.ArcGISRuntime.Symbology.SimpleMarkerSymbol { Color = Colors.Red, Size = 12, Style = Esri.ArcGISRuntime.Symbology.SimpleMarkerStyle.Circle }
var largeSym = new Esri.ArcGISRuntime.Symbology.SimpleMarkerSymbol { Color = Colors.Red, Size = 24, Style = Esri.ArcGISRuntime.Symbology.SimpleMarkerStyle.Circle
// create a default symbol for values not defined in the renderer's class definitions
var defaultSym = new Esri.ArcGISRuntime.Symbology.SimpleMarkerSymbol { Color = Colors.Gray, Size = 8, Style = Esri.ArcGISRuntime.Symbology.SimpleMarkerStyle.Circ
// create a ClassBreakInfo for each range; define the min/max attribute values and associated symbol
var classRange1 = new Esri.ArcGISRuntime.Symbology.ClassBreakInfo { Minimum = 0, Maximum = 75000, Symbol = loSym };
var classRange2 = new Esri.ArcGISRuntime.Symbology.ClassBreakInfo { Minimum = 75000, Maximum = 200000, Symbol = medSym };
var classRange3 = new Esri.ArcGISRuntime.Symbology.ClassBreakInfo { Minimum = 200000, Maximum = 9000000, Symbol = largeSym };
// create a class breaks info collection; add the info for each class
var classInfos = new Esri.ArcGISRuntime.Symbology.ClassBreakInfoCollection();
classInfos.Add(classRange1);
classInfos.Add(classRange2);
classInfos.Add(classRange3);
// create the class breaks renderer
var classBreaksRenderer = new Esri.ArcGISRuntime.Symbology.ClassBreaksRenderer();
Note: As with UniqueValueRenderer, features whose attribute value falls outside the classes defined for the
renderer are symbolized with the default symbol. If a default symbol is not defined, those features will not
display.
Temporal renderer
A temporal renderer allows you to define a set of renderers to display time-based data in interesting ways. The temporal renderer has
properties for defining an observation renderer, latest observation renderer, track renderer, and ager. Temporal renderers work with the
TimeExtent property you've defined for your map view.
Note: Temporal renderers are currently supported for layers that inherit from
GraphicsLayer.
The observation renderer defines the symbology for each observation in the layer. For a vehicle tracking application, you might choose
a unique value renderer to display each vehicle with a unique symbol. A class breaks renderer would be more appropriate for showing
earthquakes by magnitude, for example. The latest observation renderer is used to display only the most recent feature in the layer.
A temporal renderer's track renderer is used to define the symbology for lines that connect related observations. For tracking vehicle
locations, for example, you may want to show the path defined by each vehicle's observations. If using a track renderer, you'll also need
to define the observation attribute that represents the track ID.
An ager is used to determine how the symbology changes as it ages. You might want older features to appear with more transparency,
a lighter color, or with a smaller marker size, for example.
// define the breaks for each age (time range); use a unique symbol for each
var classBreak1 = new Esri.ArcGISRuntime.Symbology.TimeClassBreaks
{ MinimumAge = new TimeSpan(0, 0, 0, 0), MaximumAge = new TimeSpan(2, 0, 0, 0),
Color = Colors.Red, Opacity = 1.0, Size = 24 };
var classBreak2 = new Esri.ArcGISRuntime.Symbology.TimeClassBreaks
{ MinimumAge = new TimeSpan(2, 0, 0, 0), MaximumAge = new TimeSpan(4, 0, 0, 0),
Color = Colors.Red, Opacity = 0.8, Size = 14 };
var classBreak3 = new Esri.ArcGISRuntime.Symbology.TimeClassBreaks
{ MinimumAge = new TimeSpan(4, 0, 0, 0), MaximumAge = new TimeSpan(8, 0, 0, 0),
Color = Colors.Red, Opacity = 0.5, Size = 4 };
// assign the time breaks to the ager's breaks collection
var timeBreaks = new Esri.ArcGISRuntime.Symbology.TimeClassBreaksCollection();
timeBreaks.Add(classBreak1);
timeBreaks.Add(classBreak2);
timeBreaks.Add(classBreak3);
symbolAger.Infos = timeBreaks;
Dictionary renderer
The dictionary renderer is a renderer that works in conjunction with a symbol dictionary for displaying specialized symbols (military, for
example) in a message layer. More information about working with specialized symbols can be found in the Display military messages
topic.
Note: Classes related to specialized symbols are not available in the ArcGIS Runtime API for Store or the
ArcGIS Runtime API for Phone.
desired and use one of the following classification methods to determine the values for each break: Natural Breaks, Equal Interval,
Quantile, or Standard Deviation. You can also choose to normalize your data by percent of the total, the value of another field, or by log.
The available classification methods are described briefly below.
Natural breaksCreates classes based on natural groupings inherent in the data. Class breaks are identified that best group
similar values and that maximize the differences between classes. The features are divided into classes whose boundaries are
set where there are relatively big differences in the data values. This classification is based on the Jenks' Natural Breaks
algorithm. For further information, see Univariate classification schemes in Geospatial Analysis-A Comprehensive Guide, 3rd
edition; 2006-2009; de Smith, Goodchild, Longley.
Equal IntervalDivides the range of attribute values into equal-sized subranges. This allows you to specify the number of
intervals, and have the class breaks determined based on the value range. For example, if you specify three classes for a field
whose values range from 0 to 300, this method creates three classes with ranges of 0-100, 101-200, and 201-300. Equal
interval is best applied to familiar data ranges, such as percentages and temperature. This method emphasizes the amount of
an attribute value relative to other values. For example, it shows that a store is part of the group of stores that make up the top
one-third of all sales.
QuantileAssigns an equal number of features to each class. A quantile classification is well suited to linearly distributed data.
Because features are grouped in equal numbers in each class using Quantile classification, the resulting map can often be
misleading. Similar features can be placed in adjacent classes, or features with widely different values can be put in the same
class. You can minimize this distortion by increasing the number of classes.
Standard DeviationClassification shows you how much a feature's attribute value varies from the mean for all features. Class
breaks are created with equal value ranges that are a proportion of the standard deviation, at the chosen interval of 1, , , or
standard deviations using mean values and the standard deviations from the mean. A standard deviation classification
displayed with a two-color ramp, for example, can illustrate values above the mean (perhaps shown in blue) and values below
the mean (shown in red).
// define a ClassBreaksDefinition to use for the renderer
var classificationInfo = new Esri.ArcGISRuntime.Tasks.Query.ClassBreaksDefinition();
classificationInfo.ClassificationMethod = Esri.ArcGISRuntime.Tasks.Query.ClassificationMethod.Quantile;
classificationInfo.BreakCount = 5;
classificationInfo.ClassificationField = "pop2000";
// create and assign the base symbol to use: only the color of this symbol will change for each class break
var baseFillSym = new Esri.ArcGISRuntime.Symbology.SimpleFillSymbol
{ Style = Esri.ArcGISRuntime.Symbology.SimpleFillStyle.Solid };
classificationInfo.BaseSymbol = baseFillSym;
// create a color ramp: colors from this ramp will be used to distinguish each class
var redColorRamp = new Esri.ArcGISRuntime.Tasks.Query.ColorRamp();
redColorRamp.Algorithm = Esri.ArcGISRuntime.Tasks.Query.Algorithm.Hsv;
// all colors will be red, ramp will go from more transparent to more opaque
redColorRamp.From = Color.FromArgb(80, 255, 0, 0);
redColorRamp.To = Color.FromArgb(200, 255, 0, 0);
// assign a collection of color ramps for the classification (just one, but you could use several)
var rampCollection = new ObservableCollection<Esri.ArcGISRuntime.Tasks.Query.ColorRamp>() { redColorRamp };
classificationInfo.ColorRamps = rampCollection;
// create a new GenerateRendererParameter and assign the classification definition
var rendererParams = new Esri.ArcGISRuntime.Tasks.Query.GenerateRendererParameters();
rendererParams.ClassificationDefinition = classificationInfo;
// create a new GenerateRendererTask using the URL to the feature layer to render
var layerUri = new Uri("http://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer/2");
var generateRendererTask = new Esri.ArcGISRuntime.Tasks.Query.GenerateRendererTask(layerUri);
// generate the renderer asynchronously and await the result
var taskResult = await generateRendererTask.GenerateRendererAsync(rendererParams);
The following image shows a class breaks renderer with 5 class breaks, using the natural breaks classification method. The class
breaks renderer is for a US States layer and the classification field is the state population in the year 2000.
Related Topics
Add graphics and text
Features and graphics
Display military messages
Spatial references
Spatial references are important, and for someone new to GIS, they can appear complicated. Spatial references ensure that spatial data
for different layers or sources can be integrated for accurate viewing or analysis. When you combine layers with different spatial
references for viewing or analysis, ArcGIS Runtime SDKs attempt to handle this disparity for you by setting defaults and requesting data in
the appropriate spatial reference from services where possible. But sometimes, you'll need to know about spatial references to get things
working. Whether it's to align data together, make your map look right, improve accuracy, or just make a layer show up, understanding the
basics of spatial references can be critical.
Spatial references can be referred to by a well-known ID (WKID). Some common WKIDs are mentioned in the text below; for a more
complete description, see Spatial reference and transformation specifications in this topic.
Graphics layers
Graphics layers don't support on-the-fly reprojection of data; ArcGIS Runtime renders these layers client-side. On-the-fly reprojection
of graphics layers could require intensive processing that would slow down the map view rendering time. When you add a graphics
layer to your map, you must ensure its spatial reference is the same as that defined on the map (typically set by the basemap layer).
You also need to ensure that individual graphics added to your graphics layer have coordinates in the matching spatial reference;
otherwise, the graphics may not show up in the map view.
When using a feature service table backed by an ArcGIS for Server feature service, the server supports reprojection. When a Service
Feature Table is to be added to a MapView, be sure to set its spatial reference based on the map's spatial reference before you
initialize the table. This will ensure the data is requested from the server in the correct spatial reference. When using the ArcGIS
feature layer, when this is added to the map, ArcGIS Runtime automatically determines the correct spatial reference and requests
data from the feature service accordingly.
Your tables in the geodatabase must be in the same spatial references as the map you are adding them to, because on-the-fly
reprojection of data from these tables is not supported. If you're using the desktop workflow, ensure the ArcMap map frame is using
the desired spatial reference before you run the create runtime content tool. If you're using the services workflow, set the desired
spatial reference in the SyncTaskParameters before you generate the geodatabase. For details on the desktop and server workflows,
see Offline patterns in this guide's "Create an offline map" topic.
Feature layers from shapefile feature tables and GeoPackage feature tables
Your tables in the geodatabase need to be in the same spatial reference as the map you are adding them to; on-the-fly reprojection of
data from these tables is not supported.
If these are ArcGIS for Server map services, then the server supports reprojection on the fly. When you add an ArcGIS dynamic map
service layer to the map, ArcGIS Runtime automatically asks for the map image in the correct spatial reference for you (based on the
map's spatial reference). WMS map services, a type of dynamic map service, support a limited set of spatial references, so you
should set the spatial reference on a WMS layer before you add it to the map.
Tiled layers
Tiled layers are precached layers. At the time of caching, a spatial reference is used and is therefore predefined. It's typically not
possible to request tiled layers in a different spatial reference from that defined in the service (unless the server supports doing this on
the fly; most do not). If an ArcGIS tiled layer is added to a map in a different spatial reference, it cannot be drawn.
Edit data
When creating new features from coordinates, the coordinate values must match the spatial reference for the layer; otherwise, the
features will not show up in the correct location on the map. You can use the geometry engine to ensure coordinates are converted
correctly before they're added to a layer. For more information about the geometry engine, see Geometry operations.
Perform analysis
Geometry objects used for analysis (for example, determining spatial relationships, such as where polygons intersect) require that the
spatial reference be known before the analysis is performed. Otherwise, results may not be accurate. Likewise, it's meaningless to
compare two geometry objects or determine their spatial relationship if they have different spatial references. To display a geometry in a
map layer, the geometry must have either the same spatial reference as the layer or be projected to the layer's spatial reference. To use
two objects together, if those objects each have a spatial reference, they should have the same spatial reference.
For more information on analysis through geometry operations, see Geometry operations.
Related Topics
Geometry operations
Geographic coordinate systems
Projected coordinate systems
Asynchronous programming
Synchronous code execution proceeds in a linear path to process a queue of instructions in order. In this mode of execution, a particular
set of code in the queue cannot be executed until all instructions ahead of it have been completed. This works fine for code that completes
quickly, but it can create a bottleneck if working with processes that take longer to execute. Such bottlenecks cause frustration for users of
your app, as they make the UI unresponsive until the blocking code completes.
By contrast, code executed asynchronously does not proceed in a linear fashion. Instead, code is executed on an available thread in the
thread pool and results (if any) are returned upon completion. This allows you to off-load execution of longer-running processes, freeing
up the UI thread so the app remains responsive to user interaction.
The .NET Framework 4.5 provides a simplified asynchronous approach that allows you to write your code in the familiar logical and linear
structure that you use for synchronous code. The .NET APIs use asynchronous execution in areas where performance may be an issue,
such as web access, working with files, and media capture.
ArcGIS Runtime SDK for .NET also leverages the .NET Framework 4.5 asynchronous pattern to provide asynchronous methods
throughout the API. Although calling an asynchronous method requires slightly different syntax than a synchronous call, the new pattern
hides much of the complexity involved and allows your code to be written with a much more linear structure compared to previous
asynchronous approaches.
As mentioned previously, calls made to an asynchronous function will return Task or Task<TResult> objects, which represent ongoing
work. The task contains information about the state of the asynchronous process and, when it completes, either the final result from the
process or the exception thrown when the process failed.
To get the actual value returned from the asynchronous operation, you need to await completion of the task using the await keyword.
When execution hits a line with await, control is returned to the calling function until the task completes.
The following example shows a call to an asynchronous method (System.Net.Http.HttpClient.GetStringAsync) to get a
Task<string>. It then uses await to get the string result of the task operation.
private async Task<string> GetSiteContentAsync()
{
// use an HttpClient to get the contents of a web page
var client = new System.Net.Http.HttpClient();
// call the async method GetStringAsync to return a Task<string>
// the task will asynchronously read the contents of the specified web site
Task<string> getContentsTask = client.GetStringAsync("http://www.esri.com");
Note: Functions that use the await keyword must be marked with the async keyword in
their definition.
Although it should be avoided if possible, an async function can be defined with a void return type. A common scenario is when defining
an async event handler, whose signature must retain the void return type.
Caution: An async function with a void return type cannot be awaited, and the caller won't be able to catch any
exceptions thrown by the function.
For more information about asynchronous programming in .NET, see the MSDN article Asynchronous Programming with Async and
Await.
See Search for features for more examples of using asynchronous calls to search for features.
Sometimes, it's not the result of an asynchronous method that's important, but waiting for a particular task to complete. For example, you
may have code that depends on the loading of all layers in the map. You can await the MapView.LayersLoadedAsync method to
ensure loading of all layers is complete, as shown in the following example.
private async Task AddGraphicsAsync()
{
// wait for all layers to load
await MyMapView.LayersLoadedAsync();
// you can now work with the graphics layer
var graphicsLyr = MyMapView.Map.Layers["MyGraphicsLayer"] as GraphicsLayer;
Asynchronous tasks generally run on a background thread for your application, which may have ramifications for working with objects in
the UI. See Threading considerations for more information.
if (queryResult != null)
{
// Process results ...
}
Cancel execution
A task can be canceled during the course of its asynchronous execution by using a System.Threading.CancellationToken,
which can optionally be passed into most ExecuteAsync methods for a task. A task can be canceled manually (for example, if the user
clicks a Cancel button) or by specifying a maximum time interval that the task is allowed to run. The following code example
incorporates both techniques by setting a time limit (10 seconds) after which the task will be canceled and also calls the Cancel
method if the user clicks the Cancel button.
private System.Threading.CancellationTokenSource canceller;
private async void DoQuery()
{
var url =
"http://sampleserver5.arcgisonline.com/arcgis/rest/services/RedlandsEmergencyVehicles/FeatureServer/1";
var queryTask = new QueryTask(new Uri(url));
// Get the graphics layer in the map; set the source with the result features
var graphicsLayer = MyMap.Layers["Graphics"] as GraphicsLayer;
graphicsLayer.GraphicsSource = resultFeatures;
}
private void CancelButton_Click(object sender, RoutedEventArgs e)
{
// If the Cancel button is clicked, cancel the task using the CancellationTokenSource object
this.canceller.Cancel();
}
Canceling the task will cause a System.Threading.Tasks.TaskCanceledException to be thrown. When allowing the user to
cancel a task, you'll need to anticipate and handle these exceptions in your code.
Related Topics
Threading considerations
Guidelines, best practices, tips, and tricks
Threading considerations
When developing your ArcGIS Runtime SDK app, strive to provide responsive interaction with the user, even when your app is doing other
work. Using multiple threads of execution is one of the most powerful ways to keep your app responsive while using the processor in
between or even during user events to perform other tasks. Although the process of writing multithreaded applications has been made
significantly easier in recent versions of .NET, great care must still be taken when architecting these applications to ensure the integrity of
the application's UI and of objects created on the UI thread.
It's important to realize that even without explicitly creating additional threads, some code in your ArcGIS Runtime SDK for .NET app may
run on a background thread. Working with asynchronous tasks, for example, executes on a thread in the app's thread pool. An
understanding of threading and the relationship between threads and objects in the UI can help avoid some common pitfalls.
Threading overview
An app runs inside memory space that is allocated by the operating system, called a process. Inside of that process, one or several
autonomous units called threads are responsible for executing code as the app runs. The processor divides its time among all threads,
which are alternately paused and resumed as processor time expires or is made available. Each thread maintains the information it needs
to resume seamlessly when it is called to execute. As the amount of code running on a single thread increases, more processor cycles are
required to complete its work. At some point, performance for the app is impacted.
Every app with a user interface has a thread that is responsible for displaying UI elements and for handling user interaction with the app.
This thread is generically referred to as the UI thread. The UI thread is your pipeline to the user interface and is the only thread you can
use to surface information to the user. It also has the potential of being overworked, which immediately impacts the responsiveness of
your app from the user's perspective.
For more details about working with threads in .NET, see MSDN for Managed threading basics and Managed threading best practices.
Running an asynchronous Task also executes code on a background thread. The following example runs the function from a Task.
private async void RunOnBackgroundThread()
{
// call the static Task.Run method to create a Task to run a function in the background
var backgroundTask = Task.Run(() => { SquareIt(12); });
Any object that inherits from System.Windows.Threading.DispatcherObject has a Dispatcher property that gives you access to
the thread on which it runs. This includes objects of type System.Windows.DependencyObject and
System.Windows.Application, which means you can access the Dispatcher through the app or from any of its UI elements. To run
code on the thread associated with the Dispatcher, call the RunAsync method and pass in the code to execute.
The following example is taken from an app that shows a browser window to allow the user to enter a user name and password for OAuth
authentication. See the ArcGIS Online Services > Traffic sample in the ArcGIS Runtime SDK samples for .NET for the
complete code. The Dispatcher for the current app is used to asynchronously invoke code to run on the UI thread.
public Task<IDictionary<string, string>> AuthorizeAsync(string serviceUri, string authorizeUri, string callbackUri)
{
_tcs = new TaskCompletionSource<IDictionary<string, string>>();
You may also need to use the Dispatcher to update UI controls based on information coming from a background thread. A common
example is an event handler receiving data from a sensor (updated locations coming from a GPS device, for example). If you want to
update UI controls, such as TextBlocks, or show the information in a message box, you may need to run that code on the UI thread.
The following example updates text content in the UI when an updated location is received from a
LocationProvider.LocationChanged event.
// a handler for the MapView.LocationDisplay.LocationProvider.OnLocationChanged event
void OnLocationChanged(object sender, LocationInfo e)
{
var thisLocation = e.Location;
var locationText = "X: " + thisLocation.X.ToString() +
" Y: " + thisLocation.Y.ToString();
// use the map view's dispatcher to update a TextBlock in the UI
this.MyMapView.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() => this.CurrentLocationTextBlock.Text = locationText);
}
Note: ArcGIS Runtime automatically marshals results from a background thread to the UI in many cases, such as
updating the display of the current location as it comes from the location provider.
Note: Attempting to work with graphics layer content from a background thread throws a
System.InvalidOperationException, with a message like the following: The calling thread
cannot safely modify content of a GraphicsLayer. GraphicsLayer content should
be modified on the thread associated with the GraphicsLayer.Dispatcher
instance.
However, other objects in the API are not associated with a Dispatcher instance and therefore, new instances can be created on one
thread and passed to another. This includes graphics not added to a layer. Therefore, it is acceptable to create a collection of Graphic
objects on a thread, pass them to the UI thread, then add them to the GraphicsLayer. Once part of the layer, they can only be modified
on the UI thread.
The following example creates thousands of graphics with complex geometries on a background thread and displays them on the UI
thread.
private async void DrawBuffersButton_Click(object sender, RoutedEventArgs e)
{
// kick off creation of a large number of complex graphics on a background thread
var graphics = await Task.Run<List<Graphic>>((Func<List<Graphic>>)CreateGraphics);
// ... resumes back here on the UI thread once the task is complete
// Now add the graphicss
var graphicsOverlay = new GraphicsOverlay();
graphicsOverlay.RenderingMode = GraphicsRenderingMode.Static; // better for large numbers of graphics
graphicsOverlay.Graphics.AddRange(graphics);
MyMapView.GraphicsOverlays.Add(graphicsOverlay);
}
// Use a geodesic buffer, this returns a polygon of equal ground distance around the center point
// (circles nearer the poles appear larger on a WebMercator map)
var geodesicCircle = GeometryEngine.GeodesicBuffer(centerPoint, distance, LinearUnits.Meters);
// create a graphic to display the buffer geometry; add it to the list
var graphic = new Graphic(geodesicCircle, symbol);
graphics.Add(graphic);
}
return graphics;
}
This concept becomes increasingly beneficial for the more complex geometries like polylines and polygons. These geometries can be
constructed in the background on a separate thread, possibly using some of the GeometryEngine methods, passed to the UI thread,
and set into graphics.
Another consideration is changes to graphics are not immediately rendered in the map. There is a batching mechanism that picks up all
changed content and pushes it into the rendering pipeline in one operation. This means that when building graphics, all properties should
be set first before adding the Graphic to the GraphicsLayer. Knowing this should determine where and when you create objects that
become part of a GraphicsLayer.
Related Topics
Asynchronous programming
Tip: If you use the ArcGIS Runtime project or item templates in Visual Studio, this event will be registered in
XAML and contain an event handler in the code behind.
<esri:MapView x:Name="MyMapView"
LayerLoaded="MyMapView_LayerLoaded"
SpatialReferenceChanged="MyMapView_SpatialReferenceChanged">
<esri:Map>
...
</esri:Map>
</esri:MapView>
// this is top level method that contains all asynchronous operations that are needed when UI loads
// (ok to return void)
private async void MyInitializeAsync()
{
// Wrap initialization to try-catch block
try
{
// if a lot of work is required, consider splitting functionality into separate tasks
// and/or void methods (depending if it is async or not)
// for example ...
await DoWorkAsync();
var myWidget = await DoSomeMoreWorkAsync();
}
catch (Exception ex)
{
// ... code here to handle possible exceptions ...
}
}
// this isn't a top level method so should return Task or Task<T>
private async Task DoWorkAsync()
{
// ...
}
Caution: When possible, Task or Task<T> should be returned from your asynchronous functions. It is acceptable to
return void from an asynchronous event handler or top-level function.
For setting the initial extent in the code behind, it's recommended to use the base Viewpoint class, which has similar constructor
overloads.
// define a viewpoint with coords that define an extent and a spatial reference
mapView.Map.InitialViewpoint = new Viewpoint(new Envelope(-117.18268,32.69585,-117.13387,32.71853, SpatialReferences.Wgs84));
// define a viewpoint with a center point and scale denominator (1:50,000 in this example)
mapView.Map.InitialViewpoint = new Viewpoint(new MapPoint(-117.15,32.705,SpatialReferences.Wgs84), 50000);
Note: Setting the Map.SpatialReference property in XAML is not supported except when binding the
property to an existing SpatialReference instance.
Note: Spatial reference WKIDs can be found in the Geographic coordinate systems and Projected coordinate
systems topics.
You should avoid creating new SpatialReference instances, for example: var sr = new SpatialReference(4326);.
Create geometry
There are a couple options for creating geometry. Use the method that is best suited for your requirements and for the geometry type with
which you are working.
Note: Geometry is immutable, which means geometry instances cannot be modified
once created.
Create points
For map points, you should always use the MapPoint constructor to create new instances. The constructor requires x and y
coordinates, and has several overrides that allow you to also specify a spatial reference, a z coordinate, or an m coordinate.
// create a new MapPoint
var myMapPoint = new MapPoint(-2.345, 45.67, new SpatialReferences.Wgs84);
For consistency with other geometry types, the API includes a MapPointBuilder that you can use to create a point. This provides the
only way to create an empty MapPoint (undefined values for the x and y coordinates).
var myMapPoint = new MapPointBuilder().ToGeometry() // an empty MapPoint with NaN coordinate values
// create a polyline from a collection of segments that have a spatial reference defined (and will be used by the new polyline)
var myPolyline = new Esri.ArcGISRuntime.Geometry.Polyline(segments)
For large numbers of points, the PointCollection class provides efficient storage of coordinates and avoids the creation of many
MapPoint instances. This provides an efficient way to build up a polygon or polyline from a large number of points, perhaps read from
an external file or database, for example.
// create an empty point collection
var myPoints = new PointCollection(SpatialReferences.WebMercator);
// set the capacity if you know the maximum number of points to add
myPoints.Capacity = maxNumberOfPoints;
// repeat adding vertex coordinates directly into the PointCollection (no MapPoint instances)
while(moPoints)
{
// ... read x/y coordinate values ...
myPoints.AddPoint(x,y);
Note: You can create a multipart polygon using a list of point collections (List<PointCollection>), where
each PointCollection contains the vertices for a part (ring, in other words).
Update geometry
You can use the PolylineBuilder and PolygonBuilder classes to create and modify a new shape. The builder is best suited for
editing workflows where the user may be adding, inserting or removing parts of a geometry interactively. Because Geometry is
immutable, the builder provides a way to make changes to a working geometry. Use the ToGeometry method on PolylineBuilder
or PolygonBuilder to get the polygon or polyline from the builder.
When updating or modifying existing geometries, use PolylineBuilder and PolygonBuilder classes to modify the geometry. The
easiest way is to pass an existing geometry to the constructor for the builder.
var polylineBuilder = new PolylineBuilder(polyline); // Create builder based on existing one
polylineBuilder.Parts[0].RemoveAt(0);
polylineBuilder.AddPoint(8, 4); // adding a point to last part
Tip: If you're consistent with names for common objects in your UI (MapView, Map, layers, and so on), it will also
make it easier to copy and paste .NET code between projects.
Related Topics
Threading considerations
Asynchronous programming
Tip: In the code above, notice that all elements have either a name (x:Name) or ID property value assigned to
them. Providing values for these properties is not required but is highly recommended. If you need access
to your MapView or Map, define an x:Name value. To allow programmatic access to a layer, provide a
value for ID. The following code, for example, is only possible because values have been provided for
these properties:
var quakeLayer = MyMap.Layers["Earthquakes"] as FeatureLayer;
// -- or --
var quakeLayer = MyMapView.Map.Layers["Earthquakes"] as FeatureLayer;
You can define an initial extent in any coordinate system you want by providing a value for the SpatialReferenceID property of the
ViewpointCenter or ViewpointExtent. Doing so does not affect the spatial reference of the Map.
The following example defines an InitialViewpoint for the map using a ViewpointCenter in a geographic spatial reference
(WGS 84).
<esri:Map.InitialViewpoint>
<esri:ViewpointCenter X="-117.445" Y="33.9" SpatialReferenceID="4326" Scale="250000"/>
</esri:Map.InitialViewpoint>
The map view control provides map navigation out-of-the-box using actions such as mouse clicks and drags, rolling the mouse wheel,
and using touch gestures. This built-in behavior allows users to explore the map without additional tools cluttering the UI. MapView also
provides methods for navigating the map programmatically. See Navigate the map for more information.
Additional elements, such as symbols and renderers, can be created in your XAML. For more information and examples, see Symbols
and renderers.
myMap.InitialViewpoint = initViewPoint;
// assign the Map to the MapView's Map property
this.MyMapView.Map = myMap;
Note: A MapView can contain zero or one Map objects. Assigning a new value to the Map property will replace the
current map (if one exists) with the new one.
For additional information about working with layers programmatically, see the Add layers with code topic.
See Symbols and renderers for more information about applying symbology to features in the map.
Note: Data binding will work without defining a data context for container controls but will require that you specify
the data source explicitly for each control you want to bind.
To provide the appropriate data context for your MapView, the first step is to create a class that defines a property of type
Esri.ArcGISRuntime.Controls.Map. The following example shows a simple class (MyViewModel) that defines a single property
called Map. This property returns an Esri.ArcGISRuntime.Controls.Map and can therefore be bound to the Map property of a
MapView. When the class is instantiated, a new Map is created, a layer is added, and the initial extent is set. At run time, the local copy
of the map (_map) can be manipulated, and the changes will appear in the UI thanks to the data binding.
class MyViewModel
{
// a Map property that a MapView can bind to
private Esri.ArcGISRuntime.Controls.Map _map;
public Esri.ArcGISRuntime.Controls.Map Map
{
get { return _map; }
set { this._map = value; }
}
// constructor
public MyViewModel()
{
// on instantiating the class, create the map (data binding will be responsible for displaying it in the view)
this._map = new Esri.ArcGISRuntime.Controls.Map();
this._map.InitialViewpoint = initViewPoint;
}
}
The data context for any FrameworkElement is set with the DataContext property. Since you want the data context to be available
as soon as your controls are displayed, the constructor for your page is a good place to set the data context. The following example
creates a new instance of the MyViewModel class and assigns it as the data context for the entire page:
public MainPage()
{
this.InitializeComponent();
// create a new MyViewModel (the class constructor builds the map)
var viewModel = new MyViewModel();
// use it to set the data context for the page(and all controls it contains)
this.DataContext = viewModel;
}
Tip: If a data binding can't be resolved, perhaps because the data context is missing or the binding property
doesn't exist, the binding is ignored. No exceptions are thrown for an erroneous binding. To track down
binding problems, check the Output window in Visual Studio while debugging your app.
To bind a map to a MapView, you need to first set the data context of the map view (or its container) to an object that has a property of
type Esri.ArcGISRuntime.Controls.Map, and bind the Map to that property. The following example defines such a binding using
the MyViewModel class from an earlier example:
<esri:MapView x:Name="MyMapView" Map="{Binding Map}"/>
Related Topics
Maps and layers
Navigate the map
Add layers with code
Work with web maps
User navigation
The following table summarizes the built-in navigation capabilities of the MapView control. See the Scene navigation topic for the
interaction capabilities built into SceneView.
Pan Press and hold left button and drag Drag Arrow keys
Flick
Double tap
Note: Rotation is disabled by default. Use InteractionOptions to enable rotation in the map view, as
described in the following section.
ZoomOptions properties
IsDoubleTappedEnabledEnable or disable zoom in with a double-click of the mouse (and zoom out with a double-click
while pressing the Shift key).
IsEnabledEnable or disable all built-in zoom operations.
IsKeyboardEnabledEnable or disable zooming in or out with keyboard shortcuts (+, - keys).
IsMouseWheelEnabledEnable or disable using the mouse wheel to zoom in or out.
IsPinchEnabledEnable or disable using pinch or spread (touch) gestures to zoom in or out.
IsTwoFingerTapEnabledEnable or disable the ability to zoom out with a two fingered tap gesture (touch).
IsZoomBoxEnabledEnable or disable the ability to press the shift key to draw an envelope to zoom in to (or out from).
MouseWheelZoomInDirectionDirection of mouse wheel scrolling to zoom in to the map. Available options are
Forward (away from the user) and Backward (toward the user). The opposite direction will zoom out.
The following example sets the mouse wheel to zoom in when scrolled backward, disables keyboard zoom keys, and disables all
panning:
MyMapView.InteractionOptions.ZoomOptions.MouseWheelZoomInDirection = MouseWheelDirection.Backward;
MyMapView.InteractionOptions.ZoomOptions.IsKeyboardEnabled = false;
MyMapView.InteractionOptions.PanOptions.IsEnabled = false;
Tip: Limiting navigation for secondary maps, such as an overview map, is a good idea when using multiple
maps in your app. See the Multiple Maps topic for more information.
Navigate programmatically
You can programmatically manipulate the map display (extent, scale, rotation) regardless of the settings for InteractionOptions. This
gives you the ability to limit the navigation options available in the control while providing your own tools for interacting with the map.
The SetViewAsync method has several overloads to provide a variety of ways for you to define a new area of the map to display. In
addition to using a specified geometry, an envelope, or a center point and scale value, you can pass a Viewpoint to the method.
The Viewpoint class is used by both map view and scene view controls to display a specified geographic location. If you need to
synchronize the area displayed between a scene view and map view in your app, you can pass Viewpoint objects between these
controls. You can also get the current view point for a scene or map view using the ViewBase.GetCurrentViewpoint method.
See Set camera position programmatically for more information about working with view points for a scene and for synchronizing the
areas displayed in a map and scene view.
Note: The MapView.Rotation property is read-only. You can use it to get the current rotation applied to the
map view but not to set a new value.
Navigation events
The MapView control raises ExtentChanged and NavigationCompleted events. In general, NavigationCompleted is the best
event to handle if you want to respond each time the user navigates the map. The ExtentChanged event is much more granular and
may fire several times for a single navigation operation.
The following code handles the NavigationCompleted event to query features inside the new extent:
Related Topics
Navigate a scene
Use a MapView to display a map
Multiple maps
Tip: The web map ID is included in the URL when you view it from ArcGIS.com. For example,
http://www.arcgis.com/home/webmap/viewer.html?webmap=2ee3425c0eb045ffa0d87bfd1e16a0aa is the
web map for Redlands drinking fountains. You can copy the text that follows webmap= in the URL string for
use in your code.
If you don't know the item ID of a particular web map, you can search for web maps using keywords. Once you find an interesting web
map, you can open it using the same technique described previously.
The following code sample shows how to search for web maps with the keyword "fountain". The first match found (sorted on the average
rating) is then opened.
// open a portal
var portal = await ArcGISPortal.CreateAsync(new Uri("http://www.arcgis.com/sharing/rest"));
// create a SearchParameters object
// set it to search for "fountain", to sort descending by the average rating, and limit to 10 results
var searchParameters = new SearchParameters()
{
QueryString = "fountain",
SortField = "avgrating",
SortOrder = QuerySortOrder.Descending,
Limit = 10
};
// do the search
var searchResult = await portal.SearchItemsAsync(searchParameters);
The PopupInfo class provides properties that describe which attributes should be included, how to format their display, and whether or
not they should be editable. Associated media, such as charts and images, can also be defined for a popup.
The following example creates a new collection of attributes for display by including only those fields defined in the popup info.
After filtering a set of attributes according to the preferences set in a layer's PopupInfo, you can bind the attributes to a UI element for
display. To mimic the behavior of the web map popups, you may want to use the OverlayItemsControl. The following example shows
XAML that defines a ListView control as a map overlay. When bound to a Dictionary of attributes, the field name (key) and value will
be displayed according to the binding defined in the ItemTemplate.
<esri:MapView x:Name="MyMapView" MapViewTapped="MyMapView_Tapped">
<esri:MapView.Overlays>
<esri:OverlayItemsControl>
<ListView x:Name="PopupAttributeList" ItemsSource="{Binding}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Key}" FontWeight="Bold" FontSize="12" Foreground="Blue" Margin="10,3"/>
<TextBlock Text="{Binding Value}" FontSize="12" Foreground="Blue" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</esri:OverlayItemsControl>
</esri:MapView.Overlays>
</esri:MapView>
Related Topics
Tutorial: Access maps and content from your portal
Add layers with code
Access the ArcGIS platform
Access portal content
Search portal content
Caution: Sharing a single layer instance simultaneously between multiple maps is not supported and is likely to cause
stability or performance issues. See the Multiple maps topic for more information about working with multiple
map views in your app.
Create a layer
There are several types of layers that you can include in your map, described in the Maps and layers topic. Each of these types of layers
can be created at run time (programmatically) if needed. Depending on the type of layer you're creating, you'll need to provide values for
different properties to successfully display the layer. Some layers, such as ArcGISTiledMapServiceLayer, display data based on an
ArcGIS for Server REST endpoint for a tiled map service. Others, such as FeatureLayer, may display data from a remote source or
from a local geodatabase. GraphicsLayer does not require a data source, as the graphics it contain are stored in memory. Once a layer
has been created and values for required properties have been defined, you can add the layer for display in the map.
Note: The order in which layers draw is the same order in which they appear in the map's layer collection. The
first layer added draws first, and subsequent layers added to the collection draw on top of previous layers.
Bing layers
A BingLayer is a tiled image map service layer that allows you to work with a cached map service resource exposed by Microsoft's
Bing services. The BingLayer uses a set of SOAP proxies and value object types rather than REST. ArcGIS Runtime .NET SDK
provides a set of implementation classes that utilize the proxies and value objects internally. Use of Bing services requires that you
generate and provide a key when utilizing BingLayer components. You can obtain a key by visiting the Bing Maps Account Center.
The MapStyle property is used to indicate the type of map to display. Valid styles are Road, Aerial, or AerialWithLabels
The Culture property allows you to use maps that are labeled for a specific culture (language). US English ("en-US") is the default
culture.
The following code sample shows how to create a new Bing map layer and assign the required key. The style is set to
AerialWithLabels, and the culture to French.
Note: When using Bing Maps in your application, it's important to include attribution information. See the
Branding Guidelines from Microsoft for more information.
Feature layers
A feature layer can display data from a single layer in an ArcGIS for Server service, or it can be based on a dataset stored locally in a
geodatabase. Each feature in a feature layer has geometry and attribute information and is rendered individually in the map using native
graphics. Functionality is dependent on whether the layer was created from a map service or feature service. Feature layers support
editing capabilities, such as adding, deleting, or updating spatial and attribute characteristics of features.
For more information about editing features, see the Edit features topic.
To create a layer that uses an ArcGIS for Server service as its data source, you need to specify the URL to the service endpoint, as
discussed previously. To do so for a FeatureLayer, you create an associated ServiceFeatureTable that references the data
source (service URI). The ServiceFeatureTable exposes other properties you may find useful, such as the desired OutFields,
the Mode used to retrieve features from the server (described below), and a Where expression to filter features.
The following code sample creates a new ServiceFeatureTable, sets the ServiceUri, Mode, and Where properties, then uses
it to create a new FeatureLayer:
// create a ServiceFeatureTable from the Incidents layer in the SF311 feature service
var gdbFeatureSvcTable = await Esri.ArcGISRuntime.Data.ServiceFeatureTable.OpenAsync(
new Uri("http://sampleserver6.arcgisonline.com/arcgis/rest/services/SF311/FeatureServer/0"));
// define the query mode for retrieving features from the server
gdbFeatureSvcTable.Mode = Esri.ArcGISRuntime.Data.QueryMode.OnDemand;
When creating a FeatureLayer from an online data source (ServiceFeatureTable), you have two options, or query modes, for
how features are retrieved from the remote service for display on the client. Depending on the nature and number of the features you
want to work with, there may be performance ramifications for the mode you choose.
SnapshotRetrieves all features currently in the ServiceFeatureTable.
OnDemandRetrieves only those features needed to display the layer for the current map extent. As the extent changes,
additional features are retrieved as needed.
Caution: Settings on the server can restrict the maximum number of features returned. In that case, only the
maximum number of features are retrieved by the client rather than all features requested. While this is
true for both query modes, it is less likely to be a problem when using the OnDemand mode since a
subset of features is usually being requested.
In general, the OnDemand mode is better suited for layers that contain a large number of features. Since only the features required for
the current extent are brought to the client, performance is improved by not wasting bandwidth on data that is not immediately
required in the app.
OnDemand mode is the best option if your app needs to have all features for a layer immediately available in the client. It may also be
the best option for layers that don't contain a large number of features. In that case, a single request is required to return the features,
rather than perhaps several as the user changes the map extent. To re-query the online source (to bring in feature edits that may
have been made, for example), use the RefreshFeatures method.
To use a FeatureLayer to display features from an offline source (a local geodatabase), you need to create a new
GeodatabaseFeatureTable and point it to the geodatabase and table that represent the data source. Once in the map, there are
no functional differences between an offline and online feature layer. Both offer the same functionality, including editing capabilities,
and provide a seamless experience to your user.
See Create an offline map to learn how to create an offline data source (geodatabase) from an online feature layer.
// open a geodatabase in local storage
var localData = Windows.Storage.ApplicationData.Current.LocalFolder;
var gdbPath = localData.Path + @"\WildlifeLocal.geodatabase";
var localGdb = await Esri.ArcGISRuntime.Data.Geodatabase.OpenAsync(gdbPath);
Graphics layers
Graphics layers are app-defined layers designed for drawing dynamic features on the map. Each graphic is defined by its own individual
geometry, attributes, and symbol so that many different geometry types can coexist in one graphics layer. The graphics can be used to
hold polygons drawn by a user, display features that satisfy a user-defined query, or show a real-time Global Positioning System (GPS)
location. All graphics in a graphics layer are stored in memory and are only available while the app is running.
For more information about graphics, see the Features and graphics topic.
The following code sample creates a new graphics layer, adds it to the map, and adds a single point at the center of the map's extent:
// create a new graphics layer, give it an ID
var graphicsLayer = new Esri.ArcGISRuntime.Layers.GraphicsLayer();
graphicsLayer.ID = "MyGraphicsLayer";
// add the graphics layer to the map
MyMapView.Map.Layers.Add(graphicsLayer);
// add the graphic to the graphics layer for display on the map
graphicsLayer.Graphics.Add(pointGraphic);
For more information about adding graphics to a map, see Add graphics and text.
KML layers
Keyhole Markup Language (KML) is an XML format for describing geographic features for visualization in two dimensions (in a Map in
other words) or three dimensions (in a Scene). KML files use a .kml extension for plain KML text files or .kmz for compressed files. In
your ArcGIS Runtime apps, you can use the KmlLayer to read and display geographic information from a .kml or .kmz file, which can
be stored locally or accessed from an online source.
The following example adds a KML layer to the map showing recent earthquakes.
// create a KML layer from an online file
var sourceUri = new Uri("http://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/1.0_week_age_link.kml");
var kmlLayer = new KmlLayer(sourceUri);
// Add the kml layer to the map
MyMapView.Map.Layers.Add(kmlLayer);
Find a layer
You may need to work with a layer that was added previously to your map. To get a reference to an existing layer in the map, you can use
the layer's ID property. This is an especially common workflow for graphics layers, where you may be continuously adding, removing, or
updating graphics in the layer as your app is running.
The following code sample references a layer with an ID value of MyGraphicsLayer. The layer is then cast to the GraphicsLayer
type. If a layer with that ID doesn't exist, or is not of type GraphicsLayer, a null value is returned. If the layer is found, it is used to add
a new graphic to the map. If it is not found, a new graphics layer is created and given the ID MyGraphicsLayer.
// find a graphics layer called "MyGraphicsLayer" in the map
var graphicsLayer = MyMapView.Map.Layers["MyGraphicsLayer"]
as Esri.ArcGISRuntime.Layers.GraphicsLayer;
// if the layer doesn't exist, create it and add it to the map
if (graphicsLayer == null)
{
graphicsLayer = new Esri.ArcGISRuntime.Layers.GraphicsLayer();
graphicsLayer.ID = "MyGraphics";
Related Topics
Layer types
Maps and layers
Work with web maps
License: An app licensed at the Basic level can include viewing offline basemaps and viewing offline feature data
contained in a geodatabase. You must license your app at the Standard level if it includes any of the
following functionality: offline editing, syncing offline edits with an upload, offline routing, and offline
geocoding. See License your app for more information on license levels.
Offline patterns
Two main patterns are available for ArcGIS Runtime offline:
Services patternBest for supporting a large number of users, this pattern allows multiple offline users to edit the same data
layers and sync edits later, when online.
Desktop patternBest for supporting applications with read-only data that requires periodic updates.
Services pattern
The services pattern is best for supporting a large number of users. This pattern allows multiple offline users to edit the same data
layers and sync edits later, when online.
For operational data, you can use a sync-enabled feature service from ArcGIS for Server, ArcGIS Online, or Portal for ArcGIS to
generate the geodatabase for offline use. Through the synchronization process, you can control whether a user can upload their
changes, download others' changes, or both. This allows the application to have an up-to-date view of the data. When more than one
user is editing the same feature and the edits conflict, the last edit synchronized to the service overrides the others.
In one workflow, sometimes referred to as a pre-planned workflow, you generate the geodatabase once and load it onto your users'
devices. This workflow requires you to register a geodatabase.
For basemap data, ArcGIS tiled map services and ArcGIS Online basemaps allow for the on-demand creation of tile caches, letting you
take your basemaps offline.
Desktop pattern
The desktop pattern, which allows a user to consume ArcGIS Runtime content created in ArcGIS for Desktop, is best for supporting
apps with read-only data requiring periodic updates. This content can include features, tabular data, tile caches, network datasets for
directions, and locators. For more information on creating ArcGIS Runtime content using ArcGIS for Desktop, see Creating ArcGIS
Runtime content.
the feature service item in ArcGIS Online, and check the Sync check box. Once you have a sync-enabled feature service, you can
generate a geodatabase for your area of interest; this creates a copy of your features that you can work with offline.
To generate a geodatabase for offline use:
1. Specify parametersBefore generating a geodatabase, specify parameters for its creation, such as the area of interest.
2. Generate a geodatabaseRequest and download copies using the methods on the GeodatabaseSyncTaskclass.
3. Register a geodatabaseAfter generating the geodatabase you may need to register it.
Specify parameters
When generating a geodatabase for offline use, you supply parameters allowing you to control the following:
The layers to include in the generated geodatabase
The extent of the generated geodatabase (and the spatial reference of this extent)The extent of the geodatabase requested
from the ArcGIS feature service is typically an envelope. However, point, line, and polygon (including multipart) geometries
are supported, allowing for more complex data extractions to be defined. Regardless of the geometry type, features that
intersect with the supplied geometry are extracted.
The spatial reference of the generated geodatabase
Whether or not to include feature attachments in the generated geodatabase
The synchronization model for the geodatabaseThe synchronization model controls how edits made to the geodatabase in
the field are applied back to the feature service during synchronization. The model supported is defined by the data that was
used to create the sync-enabled feature service. If the data is non-versioned, the synchronization model is per layer. This is
the most flexible model, allowing you to synchronize on a layer-by-layer basis, based on the layers you specify. If the data is
versioned, the synchronization model is per geodatabase. This synchronizes the entire geodatabase, including all layers and
tables at once.
Whether to only include a subset of the features in the specified extent, by specifying layer queries to filter features by
attribute values
Generate a geodatabase
To request a geodatabase from a sync-enabled feature service for your area of interest, use the GeodatabaseSyncTaskclass for
this, after setting up your GenerateGeodatabaseParameters for the task.
Note: Feature attachments, if supported by the feature service, are not included in the generated geodatabase
by default. Set GenerateGeodatabaseParameters.ReturnAttachments to true if you want to
include feature attachments in the output geodatabase. For information about using feature attachments
in your ArcGIS Runtime app, see the Work with feature attachments topic.
The following code snippet shows how this can be achieved:
// provide a callback to execute when the GeodatabaseSyncTask completes (successfully or with an exception)
private async void GdbCompleteCallback(Esri.ArcGISRuntime.Tasks.Offline.GeodatabaseStatusInfo statusInfo, Exception ex)
{
Windows.UI.Popups.MessageDialog messageDialog;
// if unsuccessful, report the exception and return
if (ex != null)
{
messageDialog = new Windows.UI.Popups.MessageDialog("Offline database was not created: " + ex.Message, "Failure");
await messageDialog.ShowAsync();
return;
}
// if successful, read the generated geodatabase from the server
var client = new Esri.ArcGISRuntime.Http.ArcGISHttpClient();
var gdbStream = client.GetOrPostAsync(statusInfo.ResultUri, null);
// report success
messageDialog = new Windows.UI.Popups.MessageDialog("Offline database created.", "Success");
await messageDialog.ShowAsync();
}
// call GenerateGeodatabaseAsync, pass in the parameters and the callback to execute when it's complete
var gdbResult = await gdbTask.GenerateGeodatabaseAsync(gdbParams, GdbCompleteCallback, new TimeSpan(0,1,0), progress, cancelToken);
}
catch (Exception ex)
{
var messageDialog = new Windows.UI.Popups.MessageDialog("Unable to create offline database: " + ex.Message, "Failure");
messageDialog.ShowAsync();
}
}
In a services pattern workflow known as a pre-planned workflow, you generate the geodatabase once and load copies of it onto each
user's device.
This workflow has the following benefits:
Allows you to control which maps/geodatabase your users can select from. You can pre-load your maps/geodatabase onto
your users' devices.
Allows you to schedule the geodatabase generation for off-peak hours.
Reduces the load on the server. Multiple clients aren't generating a geodatabase for the same area because you've
generated it for them.
If you use this workflow, you must register the geodatabase (copy) on each device that uses it. For details and important tips on
registering and unregistering geodatabases, see Register a geodatabase in a pre-planned workflow in "Sync offline edits."
Caution: To read from a geodatabase while testing your app, you must enable the Internet (Client and Server)
capability in your app's Package.appxmanifest file.
Steps:
1. Open the geodatabase using the static OpenAsync method on the Geodatabaseclass, which takes the path to the
geodatabase. This class has methods that let you list the feature tables and properties in the geodatabase file.
// build the path to the geodatabase file in local storage
var localData = Windows.Storage.ApplicationData.Current.LocalFolder;
var gdbPath = localData.Path + @"\WildlifeLocal.geodatabase";
2. A feature layer is used to display features on a map. To create a feature layer from a geodatabase, first, use the
geodatabase to retrieve a feature table, and next, create a feature layer from that feature table. The geodatabase
potentially contains several geodatabase feature tables, depending on the layers you requested during geodatabase
generation. If the geodatabase was created from a sync-enabled feature service, you can retrieve a feature table by ID
corresponding to the feature service's layer ID.
// get the first geodatabase feature table
var gdbFeatureTable = gdb.FeatureTables.FirstOrDefault();
3. Add the feature layer to the map. Once the layer is added and initialized, your features display in the map.
MyMapView.Map.Layers.Add(featureLayer);
The features you will see in the map depend on the map extent displayed. If your features are not displaying, make sure
you have panned or zoomed to the appropriate extent, and that the spatial reference of the geodatabase matches the
spatial reference of the map. You can set the spatial reference of a geodatabase at generation time, as described in
Generate a geodatabase from a feature service.
Include a basemap
A basemap is a map layer that helps orient the user of the map. Typically it sits behind operational layers and shows roads and buildings
to give context to the operational layer.
Tile packages are the most convenient because the entire cache lives in a single .tpk file. However, the size of this file might be
problematic for devices that enforce a limit on file size. If this is an issue, use compact caches instead. Compact caches store the
same information as tile packages, but the data is stored in a structure of directories and files that are more suitable for some
operating systems.
RPF
SRTM1, 2
See Provide a surface for a scene for more information.
Related Topics
Editing
Edit features
Sync offline edits
Multiple maps
An app can contain more than one map. Most often, an additional map is used to display an overview of the area of interest that is being
studied on the main map. You can also use multiple maps to show the following:
Different layers of information about a specific area side by side.
The detail of an area based on the mouse or touch area of the main map.
The number of maps that can be shown is limited by your hardware. Screen size and graphics processing will dictate how many maps can
be practically used in your app. There is no hard limit imposed by the runtime.
The following XAML defines a main map and a smaller overview map (displayed in the upper-right of the page).
<Grid>
<esri:MapView x:Name="MyMapView" ExtentChanged="MyMapView_ExtentChanged">
<esri:Map>
<layers:ArcGISTiledMapServiceLayer ID="Basemap"
ServiceUri="http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer"/>
</esri:Map>
</esri:MapView>
<esri:MapView x:Name="MyOverviewMapView"
Width="150" Height="100"
HorizontalAlignment="Right" VerticalAlignment="Top">
<esri:MapView.InteractionOptions>
<esri:InteractionOptions IsEnabled="False"/>
</esri:MapView.InteractionOptions>
<esri:Map>
<layers:ArcGISTiledMapServiceLayer ID="Basemap"
ServiceUri="http://services.arcgisonline.com/ArcGIS/rest/services/World_Shaded_Relief/MapServer"/>
</esri:Map>
</esri:MapView>
</Grid>
Note: You may want to disable user interaction (panning, zooming, rotating) with the overview map so the extent
shown is always based on the extent in the main map view. Use the MapView.InteractionOptions
property as shown in the previous example to disable user interaction. See the Navigate the map topic for
more information about restricting the built-in map interaction.
Code in the ExtentChanged event for the main map updates the overview map to display the same location at a smaller scale (larger
map area).
void MyMapView_ExtentChanged(object sender, EventArgs e)
{
// display the overview map at an extent 4 times larger than the main map extent
MyOverviewMapView.SetViewAsync(MyMapView.Extent.Expand(4));
}
To display an outline representing the current extent of the main map in the overview map, you must include a graphics layer and a
graphic component in your overview map. In the extent changed event, after updating the extent of the overview map, you can set the
extent graphic to show the current extent of the main map. The following example adds an extent graphic to a graphics layer in the
overview map when the page initializes. The geometry of the graphic is then updated when the main map view extent changes.
private Graphic overviewExtentGraphic;
public MainWindow()
{
InitializeComponent();
overviewExtentGraphic = new Graphic(MyMapView.Extent,
FindResource("RedBoxSym") as SimpleFillSymbol);
var graphics = MyOverviewMapView.Map.Layers["ExtentGraphicsLayer"] as GraphicsLayer;
graphics.Graphics.Add(overviewExtentGraphic);
}
Side-by-side maps
Side-by-side maps are a great way to show different layers of information at the same time. For example, you can compare imagery with
topographic information, display before-and-after images, or show different levels of detail side by side.
The recommended approach when sharing extents between multiple maps is to disable interaction for all but one map, and allow that
interaction to control updates to all other (dependent) maps. Map interaction is enabled by default, but can be disabled by setting the
MapView.InteractionOptions.IsEnabled property to False, as shown in the following XAML.
<esri:MapView.InteractionOptions>
<esri:InteractionOptions IsEnabled="False"/>
</esri:MapView.InteractionOptions>
You can set the extent of the dependent maps in code that handles the ExtentChanged or NavigationCompleted event.
void MapViewOne_NavigationCompleted(object sender, EventArgs e)
{
MapViewTwo.SetViewAsync(MapViewOne.Extent);
}
Detail map
Using an overview as your main map and showing detail in a separate window might be useful when you have multiple project sites
spread apart geographically. You can define each map to have different layers of information, or they can have the same map layers but
shown at a different scale.
To define a detail map that is related to a main map, the same methodology that was described for an overview map is used. The extent of
the detail map is dependent on the extent of the main map, but at a fraction of the scale. In the following example, the detail map uses a
scale of 10 percent of the main map.
void MyMainMapView_NavigationCompleted(object sender, EventArgs e)
{
var detailExtent = MyMainMapView.Extent.Expand(0.1);
MyDetailMapView.SetViewAsync(detailExtent);
MyDetailMapView2.SetViewAsync(detailExtent);
MyDetailMapView3.SetViewAsync(detailExtent);
}
The Envelope.Expand method takes a value greater than 0. Values less than 1 result in a smaller envelope, values greater than 1
produce a larger extent. In the previous example, the value of 0.1 will show the map at a much larger scale (smaller map area) than the
main map.
A way to achieve a similar outcome without the addition of a second map component to your app is to use the map magnifier. The map
magnifier is a property of the map component. Although the default is false, if you add the property with a value of true to your map, when
you tap and hold on the map, a circular window appears and magnifies that area of the map.
<esri:MapView x:Name="MyMainMapView" ShowMagnifierOnTapAndHold="True">
...
</esri:MapView>
The map magnifier will only magnify the layers that are contained in the main map. If different layers are required, a second map
component is required.
Note: Location display can only be enabled in a single map view in your app at a time. If you attempt to enable
location display in several map views simultaneously, it will only appear in one.
Related Topics
Navigate the map
Use a MapView to display a map
Note: Symbology defined for individual graphics will override rendering defined for the
GraphicsLayer as a whole.
A map can contain any number of graphics layers. A GraphicsLayer, in turn, can store any number of Graphic objects in its
GraphicsCollection, exposed via the layer's Graphics property. The GraphicsCollection is useful, as it provides methods for
adding and removing individual graphics in the layer.
GraphicsLayers can be created and added to a map using XAML or code. The following examples illustrate both ways of creating and
adding a GraphicsLayer to the map.
Add a GraphicsLayer using XAML
<!-- With the following xml namespaces defined-->
<!-- xmlns:esri="using:Esri.ArcGISRuntime.Controls"
xmlns:layers="using:Esri.ArcGISRuntime.Layers"
-->
<esri:MapView x:Name="MyMapView">
<esri:Map x:Name="MyMap">
<layers:ArcGISTiledMapServiceLayer ID="BaseLayer"
ServiceUri="http://services.arcgisonline.com/arcgis/rest/services/World_Street_Map/MapServer"/>
<layers:GraphicsLayer ID="MyGraphics"/>
</esri:Map>
</esri:MapView>
Note: If you will need to refer to one of your map's layers in code, it's a good idea to provide a unique value for its
ID property. Since graphics can only be added programmatically, this property can be especially useful
when defining a GraphicsLayer.
You may want to simply create and add the GraphicsLayer if it is not found in the map, as shown in the following code:
var graphicsLayer = MyMap.Layers["MyGraphics"] as Esri.ArcGISRuntime.Layers.GraphicsLayer;
if (graphicsLayer == null)
{
graphicsLayer = new Esri.ArcGISRuntime.Layers.GraphicsLayer();
graphicsLayer.ID = "MyGraphics";
MyMap.Layers.Add(graphicsLayer);
}
Once a graphics layer is in the map, you can add graphics by following this basic process:
1. Create a Graphic object and assign the Geometry you want to display. Make sure the spatial reference for the geometry
matches that of the map.
2. Define a Symbol appropriate for the type of geometry used for the graphic (for example, marker, line, or fill symbol). This step is
not required if a Renderer has been assigned to the GraphicsLayer.
3. Optionally, define and assign a collection of attributes describing the Graphic. This may be required if your GraphicsLayer
uses a renderer that depends on a specific attribute value (such as a class breaks renderer or unique value renderer).
4. Add the new Graphic to the GraphicsLayer.
A PictureMarkerSymbol symbolizes a point using an image from a local source (such as a .png file on disk or stored in your project's
resources) or from an online source (specified with a URI). Along with the image, you can also specify a rotation angle, size (width and
height), opacity, and an offset to apply when drawing the symbol.
The following example uses the MapViewTapped event on the MapView to create a Graphic at the location touched on the map. The
graphic is symbolized with a red circle and added to the GraphicsLayer.
Tip: For most use cases, it's recommended that you use methods on the Editor object to return geometry from
the user, rather than mouse and touch events on the MapView. An example of using the Editor
RequestShapeAsync method is shown below.
The following example calls RequestShapeAsync on the Editor object to get a Polyline from the user. After the line is drawn, a
Graphic is created to display it with a dashed blue line symbol.
// use the MapView's Editor to get polyline geometry from the user
var line = await MyMapView.Editor.RequestShapeAsync(Esri.ArcGISRuntime.Controls.DrawShape.Polyline,
lineSymbol, null);
The following examples illustrate creating polygon shapes and symbolizing them with fill symbols.
The important thing to note is that the entirety of these (visually distinct) shapes are conceptually one object defined as a single
geometry: a multipart polygon. The geometry shown above was constructed using the following code:
// define a picture fill symbol from a png file in the project's assets folder
var pictureSym = new Esri.ArcGISRuntime.Symbology.PictureFillSymbol();
await pictureSym.SetSourceAsync(new Uri("ms-appx:///Assets/donut.png"));
pictureSym.Height = 30.0;
pictureSym.Width = 30.0;
pictureSym.Outline = null;
Add text
Add text to the map by assigning a TextSymbol to a graphic. Point graphics are best suited for displaying text, as the geometry will
define the horizontal and vertical center of the text. To modify where the text appears relative to its point geometry, use the
HorizontalTextAlignment and VerticalTextAlignment properties on the TextSymbol. A TextSymbol, however, can be
applied to a graphic of any geometry type. For Polygon or Polyline, by default the text will appear at the center of the geometry's
bounding envelope (Extent), but you can adjust the text's alignment in the same way as with point geometries.
Tip: If you want the geometry (such as a point) to appear along with the text you're going to add, you may need
to create two graphicsone to display the text (symbolized with a TextSymbol) and another to display the
point (symbolized with a SimpleMarkerSymbol or PictureMarkerSymbol). Another option is to define
labels for your graphics layer, which is described later in this topic.
The Text property on the TextSymbol stores the text you want to display. You can assign a particular Font, which includes the size,
style (italic, underlined), and weight (bold, normal) for the text. You can set the Color for the text, as well as the BackgroundColor and
Angle.
The following example adds a point and text to identify Cleveland's Rock and Roll Hall of Fame:
Note: The angle of the text in a TextSymbol is measured clockwise from horizontal. The Angle property
specified in the code above (-60) can also be expressed as 300.
Label a graphics layer
If you simply want to add some ad hoc text to your map, then adding a marker graphic with a TextSymbol to define the desired text and
font provides a quick and easy way to accomplish that. If, however, you want to display text for all features in a graphics layer (based on
an attribute value, for example), you need to define labeling for the GraphicsLayer.
Graphics can be labeled according to label classes. A label class defines the text to display for labels and the symbol used to display
them. Label text can be defined as any combination of hard-coded text and attribute values, and label symbology is defined using the
same TextSymbol object used for adding simple text graphics, as previously described.
GraphicsLayer has a Labeling property with a LabelClasses collection that can contain zero or several LabelClass objects. Each
LabelClass in the collection can define a unique set of labels to draw for the layer. The IsEnabled property on the Labeling class is
used to turn labels on or off by providing the appropriate Boolean value (true or false).
The following example creates an AttributeLabelClass to define labeling for restaurants displayed as point graphics. The
TextExpression property is used to define a label that shows the name of the restaurant along with its rating on a separate line. The
Symbol property defines a symbol with a blue bold font surrounded by a light blue halo. Finally, the label class is added to the graphics
layer's collection, and the IsEnabled property is set to true to display the labels.
// enable labeling
graphicsLayer.Labeling.IsEnabled = true;
// create new UniqueValueInfos: provide attribute value (food type) and symbol to use
var info1 = new Esri.ArcGISRuntime.Symbology.UniqueValueInfo("Chinese", chineseSym);
var info2 = new Esri.ArcGISRuntime.Symbology.UniqueValueInfo("American", americanSym);
var info3 = new Esri.ArcGISRuntime.Symbology.UniqueValueInfo("Italian", italianSym);
// assign the renderer to the graphics layer and add the layer to the map
graphicsLayer.Renderer = uniqueRenderer;
MyMap.Layers.Add(graphicsLayer);
The following is an example of point graphics displayed with a unique value renderer and symbolized with picture marker symbols.
For the renderer example above to display graphics as expected, the graphics must have a "FoodStyle" attribute. The following example
shows how to add attributes when creating a graphic:
var attributes = new Dictionary<string, object>();
attributes.Add("Name", "Dougherino's");
attributes.Add("Address", "123 Center Street");
attributes.Add("Rating", 8.5);
attributes.Add("FoodStyle", "Italian");
var markerGraphic = new Esri.ArcGISRuntime.Layers.Graphic(mapPoint, attributes);
A ClassBreaksRenderer can be used to display graphics according to discrete ranges of an attribute value. The following example
illustrates how to create a ClassBreaksRenderer at design time with XAML to display three classes of restaurant points according to
their rating: 0-5, 5-8, 8-10.
<!-- With the following xml namespace defined-->
<!-- xmlns:sym="using:Esri.ArcGISRuntime.Symbology"
-->
<Grid.Resources>
<!--Define the renderer and its symbols in the Resources section-->
<sym:SimpleMarkerSymbol x:Key="AvoidMarkerSym" Color="Red" Style="X" Size="10"/>
<sym:SimpleMarkerSymbol x:Key="OkMarkerSym" Color="Yellow" Style="Circle" Size="12"/>
<sym:SimpleMarkerSymbol x:Key="GoodMarkerSym" Color="Green" Style="Circle" Size="14"/>
<sym:SimpleRenderer x:Key="SR" Symbol="{StaticResource AvoidMarkerSym}"/>
<sym:ClassBreaksRenderer x:Key="RestaurantRatingRenderer" Field="Rating">
<sym:ClassBreakInfoCollection>
<sym:ClassBreakInfo Symbol="{StaticResource AvoidMarkerSym}" Minimum="0.0" Maximum="5.0"/>
<sym:ClassBreakInfo Symbol="{StaticResource OkMarkerSym}" Minimum="5.1" Maximum="8.0"/>
<sym:ClassBreakInfo Symbol="{StaticResource GoodMarkerSym}" Minimum="8.1" Maximum="10.0"/>
</sym:ClassBreakInfoCollection>
</sym:ClassBreaksRenderer>
</Grid.Resources>
<!-- ... -->
<!-- Apply the Renderer in the XAML for the GraphicsLayer-->
<esri:GraphicsLayer ID="MyGraphics" Renderer="{StaticResource RestaurantRatingRenderer}"/>
Manipulating graphics
Once a graphics layer has been added to the map and populated with various graphics, you may need to further manipulate the graphics
by removing or reording them, allowing the user to select or unselect them, or moving them around the map.
Similarly, the Remove method will remove a graphic from the collection, taking a graphic object as an argument, rather than its index
position. The following example verifies that the graphic exists in the collection before removing it:
if (graphicsLayer.Graphics.Contains(this.myGraphic))
{
graphicsLayer.Graphics.Remove(this.myGraphic);
}
When drawing several graphics within a single graphics layer, you may need to move certain graphics to display on top of others.
Perhaps you need to emphasize graphics with a particular attribute, such as restaurants of a particular type, for example. To make sure
those graphics draw on top, you can give a value for each graphic's ZIndex property that is larger than the other graphics' ZIndex
values. Since ZIndex defaults to 0, you can set a value of 1 to move a graphic above the others.
The following example shows how to display selected graphics on top of all others in the layer (assuming all graphics in the layer have
the default value of 0 for ZIndex):
foreach (var graphic in graphicsLayer.SelectedItems)
{
graphic.ZIndex = 1;
}
Next, the timer's callback function,timer_Tick, is used to loop through all graphics. For point graphics, a random value between 0 and
1 is multiplied by 50 map units (meters for example) to create an x and a y offset. The MoveTo method is then called on the underlying
Point to update the graphic's position with the new coordinate values. Notice that if the animate flag is false, the callback will not run.
This flag can be used to start and stop animation as required.
private async void timer_Tick(object state)
{
if (!animate) { return; }
point.MoveTo(newX, newY);
}
}
});
Note: To marshal between the UI thread and the worker thread that System.Threading.Timer is running on,
you'll need to call RunAsync on the application's Dispatcher as shown above.
Tip: Using MoveTo is more efficient that completely updating the graphic's geometry (that is, replacing it with a
new MapPoint). When animating many graphics on the map, MoveTo will perform better.
Finally, a button click is used to start the animation by setting the value of the animate flag to true. This code toggles the Boolean
value of the flag, so a second click can be used to stop the animation.
private void AnimateButton_Click(object sender, RoutedEventArgs e)
{
// toggle the value of the animate flag
this.animate = !this.animate;
this.AnimateButton.Content = this.animate ? "Stop Animation" : "Start Animation";
}
Note: Because positive x and y offsets are always being added to the current coordinate values, the code above
will always move points in a northeasterly direction. To better randomize the movement, you can randomly
negate the value of deltaX and deltaY.
Related Topics
Features and graphics
Search for features
Symbols and renderers
Note: In each of the code examples in this topic, the following XML namespace references
are assumed:
xmlns:esri="using:Esri.ArcGISRuntime.Controls"
xmlns:lyr="using:Esri.ArcGISRuntime.Layers"
xmlns:data="using:Esri.ArcGISRuntime.Data"
xmlns:sym="using:Esri.ArcGISRuntime.Symbology"
The following example uses a single label class for all point features (United States cities). All labels use the same symbol and attribute
(areaname).
<lyr:FeatureLayer ID="Cities" >
<data:ServiceFeatureTable ServiceUri="http://sampleserver5.arcgisonline.com/arcgis/rest/services/USA/MapServer/0"/>
<lyr:FeatureLayer.Labeling>
<lyr:LabelProperties IsEnabled="True">
<lyr:AttributeLabelClass TextExpression="[areaname]" LabelPlacement="PointAboveCenter">
<sym:TextSymbol Color="white">
<sym:SymbolFont FontFamily="Segoe" FontSize="14" FontWeight="Bold"/>
</sym:TextSymbol>
</lyr:AttributeLabelClass>
</lyr:LabelProperties>
</lyr:FeatureLayer.Labeling>
</lyr:FeatureLayer>
Note: Attribute values in a labeling expression are identified by placing the attribute field name in
square brackets.
There are several aspects of label behavior that you can control for a label class.
TextA label expression can be used to determine the text to display for each feature in the label class. The label text can come
from a combination of available attributes and hard-coded text. A label showing length in feet stored in an attribute named
length_ft, for example, may look like this: [length_ft] CONCAT \" feet\". A feature with a length_ft value of 343
would result in a label of 343 feet.
Tip: Label expressions are evaluated on the server and use the keywords and syntax described in the
ArcGIS Server REST API documentation.
SymbolThe font, size, color, angle, and so on, used to display labels in the class. You can also provide a border or background
for the label symbol.
Maximum scaleThe largest scale at which labels in the class are shown. This value represents the scale denominator for the
zoomed-in scale; a value of 0 means a maximum scale is not applied.
Minimum scaleThe smallest scale at which labels in the class are shown. This value represents the scale denominator for the
zoomed-out scale; a value of 0 means a minimum scale is not applied.
PlacementLabels can be placed at a specified position relative to the features they describe. There are different options for
placement depending on the geometry of the feature being labeled. Line features, for example, may have labels placed above the
center of the line, below the center of the line, above the end point, and so on.
PositionLogic for positioning labels can be controlled using a variety of options, such as whether they should be allowed to
overlap with features in the layer.
PriorityA label class can be given a priority relative to other labels in the layer. If labels from different classes conflict in their
placement, the label from the highest-priority class will be displayed.
WHERE clauseThe features that belong in a label class are determined by evaluating an attribute expression. If using a single
label class for a layer, there is no need to explicitly define this expression. When using multiple label classes, however, it's
important to define WHERE clauses that uniquely assign features for each class.
Creating multiple label classes is useful when you want to distinguish labels for certain types of features on the map. When labeling cities,
for example, you may want to display capital cities with a larger font or different color. The following example uses two label classes to
make labels for state capitals stand out.
<lyr:FeatureLayer ID="Cities" >
<data:ServiceFeatureTable ServiceUri="http://sampleserver5.arcgisonline.com/arcgis/rest/services/USA/MapServer/0"/>
<lyr:FeatureLayer.Labeling>
<lyr:LabelProperties IsEnabled="True">
<lyr:AttributeLabelClass WhereClause="capital = 'N'" TextExpression="[areaname]" LabelPlacement="PointAboveCenter">
<sym:TextSymbol Color="OldLace">
<sym:SymbolFont FontFamily="Segoe" FontSize="14" FontWeight="Bold"/>
</sym:TextSymbol>
</lyr:AttributeLabelClass>
<lyr:AttributeLabelClass WhereClause="capital = 'Y'" TextExpression="[areaname]" LabelPlacement="PointAboveCenter">
<sym:TextSymbol Color="white">
<sym:SymbolFont FontFamily="Segoe" FontSize="18" FontWeight="Bold"/>
</sym:TextSymbol>
</lyr:AttributeLabelClass>
</lyr:LabelProperties>
</lyr:FeatureLayer.Labeling>
</lyr:FeatureLayer>
Label visibility can be controlled for individual label classes or for the entire layer (all label classes). Labels are not displayed when layer
features are not visible.
</lyr:ArcGISDynamicMapServiceLayer>
You can also work with the DynamicLabelingInfo class programmatically. The following example adds a new set of labels for cities
with a population less than 50,000.
// Minor city label info
DynamicLabelingInfo minorCityLabelInfo = new DynamicLabelingInfo();
minorCityLabelInfo.LabelExpression = "[areaname]";
minorCityLabelInfo.LabelPlacement = LabelPlacement.PointAboveCenter;
minorCityLabelInfo.Symbol = new Esri.ArcGISRuntime.Symbology.TextSymbol()
{
Color = Colors.Black,
Font = new SymbolFont("Arial", 12, SymbolFontStyle.Normal, SymbolTextDecoration.None, SymbolFontWeight.Normal)
};
minorCityLabelInfo.Where = "pop2000 <= 50000";
minorCityLabelInfo.MaxScale = 0;
minorCityLabelInfo.MinScale = 5000000;
Related Topics
Display map overlays
Add graphics and text
Caution: Map overlays are designed to display a limited number of elements on the map. Displaying too many items
in the map overlays collection will produce poor display performance for your app.
When to use overlays
ArcGIS Runtime SDK for .NET provides several options for rendering things on a map. Each display option is designed to accommodate
specific use cases that your app may require, and to ensure optimal performance for your app. You should know the advantages and
drawbacks for each display option so you can use the proper tool for each scenario. The following descriptions provide an overview of the
options available for displaying dynamic content in the map view.
Map overlaysUsed to display UI elements anchored to a location on the map (often called MapTips). They are built from
FrameworkElement objects and require more resources to render than features or graphics. Map overlays give you the ability to
design rich UI elements combining text, images, and various controls and are designed to display a small number of elements
over the map (less than 20 or so). Map overlay elements always display on top of any other objects displayed in the map view.
Graphics overlaysAllow you to associate a collection of Graphic elements with the MapView. Graphics have geometry and
attributes that are stored in memory; consequently, they must be built programmatically and aren't persisted. A
GraphicsOverlay always displays on top of all layers in the map but below any map overlay elements. It displays over any Map
you put in the map view and will automatically adjust if the spatial reference changes. While a graphics overlay can display more
elements than a map overlay, because they are stored in memory, graphics overlays are designed to display a moderate number
of features that belong more with your app rather than with a particular map. A GraphicsOverlay is best suited for displaying
map information that is specific to the current user session or things that need to be displayed temporarily. Showing query results
or buffer polygons on the map are examples suited to using a GraphicsOverlay.
Note: Because they are not in the map, graphics in overlays will not appear in a map's legend or be
displayed when the map is printed.
Graphic layersAlso contain a collection of Graphic elements but differ from a GraphicsOverlay because the graphics are
used to represent data in the Map rather than temporary elements in the MapView. A GraphicsLayer is added to a map's layer
collection, and the position of graphics within the map display depends on the position of the layer within the collection. If added as
the last layer in the collection, a GraphicsLayer will display on top of all other layers in the map but below any graphics overlays
or map overlay elements. Tracking a fleet of vehicles or showing stops along a route are examples suited to using a
GraphicsLayer.
Feature layersDisplay a collection of Feature objects. A Feature is similar to a Graphic in that they both have geometry and
attributes that describe a location (as a point, line, or polygon). Unlike graphics, which are stored in memory, features are stored
physically in a table and are persisted between sessions. For this reason, features are better suited for displaying a common set of
data to all users of your app and between user sessions. Using features instead of graphics can dramatically reduce memory
usage and are ideal for working with large datasets and on devices that have limited memory available. A FeatureLayer
provides the best available performance and is designed to display several thousands of features quickly and efficiently.
Note: For a more detailed comparison of features and graphics, see the Features and
graphics topic.
Note: In each of the code examples in this topic, the following xml namespace references
are assumed:
xmlns:esri="using:Esri.ArcGISRuntime.Controls"
xmlns:lyr="using:Esri.ArcGISRuntime.Layers"
<esri:MapView x:Name="mapView">
<esri:Map>
<lyr:ArcGISTiledMapServiceLayer
ServiceUri="http://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer" />
</esri:Map>
<esri:MapView.Overlays>
<esri:OverlayItemsControl>
<TextBlock x:Name="utahMapTip"
Text="Somewhere in Utah"
FontWeight="Bold" Foreground="White"
Visibility="Collapsed"/>
</esri:OverlayItemsControl>
</esri:MapView.Overlays>
</esri:MapView>
Use code to position your map overlay when the app is running. You may want to show an overlay when the user clicks a location on the
map or in response to some other UI interaction. You may want to show an overlay when the application initializes, as shown in the
following example:
public MainPage()
{
this.InitializeComponent();
// handle the Loaded event for the MapView to position the map overlay
this.MyMapView.Loaded += SetMapTip;
}
The following example creates and positions the same overlay using code:
var tb = new TextBlock();
tb.Foreground = new SolidColorBrush(Colors.White);
tb.FontWeight = FontWeights.Bold;
tb.Text = "Somewhere in Utah";
In the previous example, the location of the overlay element is set by calling a static method on the MapView class. This is because the
ViewOverlayAnchor property is an attached property defined in the map view. To get the current location of an overlay element, call
MapView.GetViewOverlayAnchor, and pass in a reference to the overlay element. To set a new position, call
MapView.SetViewOverlayAnchor, and pass in the element and a map point for the new location. This is the technique you'll use when
moving an overlay according to user interaction, such as a tap or mouse click on the map.
<esri:MapView.Overlays>
<esri:OverlayItemsControl>
<Grid x:Name="ferneyOverlay"
HorizontalAlignment="Right" VerticalAlignment="Top"
MaxWidth="200"
Visibility="Collapsed">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="20" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
The location of the overlay can be defined at run time. The following example shows how to find specific map overlay elements by name
and set their position:
MapPoint overlayLocation = null;
// find each overlay element from the MapView using its name
var ferneyTip = this.MyMapView.FindName("ferneyOverlay") as FrameworkElement;
var utahTip = this.MyMapView.FindName("utahMapTip") as FrameworkElement;
// if the overlay element is found, set its position and make it visible
if (ferneyTip != null)
{
overlayLocation = new Esri.ArcGISRuntime.Geometry.MapPoint(6.1081, 46.2558, Esri.ArcGISRuntime.Geometry.SpatialReferences.Wgs84);
Esri.ArcGISRuntime.Controls.MapView.SetViewOverlayAnchor(ferneyTip, overlayLocation);
ferneyTip.Visibility = Visibility.Visible;
}
if (utahTip != null)
{
overlayLocation = new Esri.ArcGISRuntime.Geometry.MapPoint(-112.19568, 39.05660, Esri.ArcGISRuntime.Geometry.SpatialReferences.Wgs84);
Esri.ArcGISRuntime.Controls.MapView.SetViewOverlayAnchor(utahTip, overlayLocation);
utahTip.Visibility = Visibility.Visible;
}
Caution: You may be tempted to get a reference to your overlay element in your code behind using syntax such as
var overlay = this.MyOverlayElement. Although this will work at design time, and you will not get
build errors when running, the reference (for example, overlay variable) will be null when your app runs.
This is because objects inside the MapView control are not in the page's control hierarchy and, therefore,
cannot be referenced from the page. Instead, you must use the FindName method on your map view to get
a reference to a specific overlay element as shown in the previous example.
Using a container element as your map overlay gives you more options for formatting backgrounds and borders. In the previous example,
a dark background color makes the text more readable. Border and Path elements are used to create a callout effect and to help
pinpoint the map location associated with the overlay element.
If the data context was from point features, you could also bind the overlay anchor position to the Geometry property using XAML as
shown in the following example. The ViewBase.ViewOverlayAnchor property requires a point, so this binding will not work for
polygon or polyline features.
<Border x:Name="countyMapTip" Background="#CC000000" BorderThickness="1" BorderBrush="White"
esri:ViewBase.ViewOverlayAnchor="{Binding Geometry}">
<StackPanel Margin="10">
<TextBlock Text="{Binding Attributes[name]}"
FontWeight="Bold" FontSize="26" Foreground="White" />
<TextBlock Text="{Binding Attributes[state_name]}"
FontSize="16" Foreground="LightGoldenrodYellow" />
</StackPanel>
</Border>
To update the information in the overlay, you need to set the data context for the countyMapTip element with a Graphic object. To
show the information, the Graphic must have name and state_name attributes.
Tip: If a property is not available in an object used in your binding, the data will not appear for the bound
properties, but an exception will not be thrown by the app. To track down data binding issues, check the
Visual Studio Output window as the app is running your data binding code. Messages regarding data
binding issues will be shown here.
The following example queries a map service layer of United States counties with a point clicked by the user. If the query returns a
result, the graphic is bound to the map overlay element (countyMapTip). The data binding defined for this element in the previous
example displays name and state_name attributes for the graphic.
private async void mapView_Tapped(object sender, TappedRoutedEventArgs e)
{
// get the map overlay element by name
var mapOverlay = this.MyMapView.FindName("countyMapTip") as FrameworkElement;
// get the location tapped on the map
var screenPoint = e.GetPosition(this.MyMapView);
var mapPoint = this.MyMapView.ScreenToLocation(screenPoint);
// create a task to query the US counties layer with the map point
var uri = new Uri("http://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer/3");
var queryTask = new Esri.ArcGISRuntime.Tasks.Query.QueryTask(uri);
The previous example works well to update the information displayed in the overlay but does not update the overlay position on the map
(anchor point).
To use the attached properties described in the previous example, you need to pass in a reference to the FrameworkElement that
serves as your map overlay. Use the FindName method on the MapView (defined on the FrameworkElement base class) to get the
overlay element using the name you assigned in XAML.
The following example builds on code in a previous example to move the MapTip element (countyMapTip) to the location clicked by
the user. The overlay element will also be shown or hidden depending on whether or not a feature was found by the click.
private async void mapView_Tapped(object sender, TappedRoutedEventArgs e)
{
// get the map overlay element by name
var mapOverlay = this.MyMapView.FindName("countyMapTip") as FrameworkElement;
// create a task to query the US counties layer with the map point
var uri = new Uri("http://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer/3");
var queryTask = new Esri.ArcGISRuntime.Tasks.Query.QueryTask(uri);
For samples that illustrate the use of map overlays, including the display of MapTips for a feature layer, see the ArcGIS Runtime SDK
for .NET samples repository.
Related Topics
Add graphics and text
Label map features
You can turn location display on and off as your app is running by setting the LocationDisplay.IsEnabled property. The following
example shows code for a check box to toggle location display:
private void ShowLocationCheckBox_Click(object sender, RoutedEventArgs e)
{
// turn location display on/off with a CheckBox
var checkBox = sender as CheckBox;
this.MyMapView.LocationDisplay.IsEnabled = (checkBox.IsChecked == true);
}
You may want your app to respond to new locations as they are provided. Perhaps you want to display additional information that
describes the location, such as speed or estimated accuracy of the position. The following example shows information about new locations
in TextBlock controls as the location is updated. MapView.SetViewAsync is then used to zoom to the location's position.
private void GetLocationChange()
{
// get the location provider; handle the location change event
var lp = this.MyMapView.LocationDisplay.LocationProvider;
lp.LocationChanged += OnLocationChanged;
}
private void OnLocationChanged(object sender, Esri.ArcGISRuntime.Location.LocationInfo e)
{
// when a new location comes in, show info to user, zoom to location
this.HeadingTextBlock.Text = e.Course.ToString();
this.SpeedTextBlock.Text = e.Speed.ToString();
this.XTextBlock.Text = e.Location.X.ToString();
this.YTextBlock.Text = e.Location.Y.ToString();
this.MyMapView.SetViewAsync(e.Location);
}
StartAsyncA method to start providing locations. As locations are read, they are exposed by raising the LocationChanged
event.
StopAsyncA method to stop providing locations. This should cease LocationChanged events from being raised.
The following example provides a template for implementing the interface in your custom location provider class. Depending on the
specifics of your custom provider, some of the details of your implementation may vary.
class MyLocationProvider : Esri.ArcGISRuntime.Location.ILocationProvider
{
// perhaps use a flag variable to enable/disable returning locations
private bool enableLocations;
// store a reference to the current location
private LocationInfo newLocation;
public MyLocationProvider()
{
// in the constructor, set up your internal location providing logic
// for example:
// connect to a GPS device
// prepare to read a file that "plays back" locations recorded in the field
// set up a timer that will periodically generate a random location for testing
}
public Task StartAsync()
{
// code here to start collecting locations
// perhaps a flag is set to enable firing the LocationChanged event
// for example:
this.enableLocations = true;
return Task.FromResult<bool>(true);
}
public Task StopAsync()
{
// code here to stop collection locations
// perhaps a flag is set to disable firing the LocationChanged event
// for example:
this.enableLocations = false;
return Task.FromResult<bool>(true);
}
For an example of using LocationDisplay in your app and of creating a custom location provider, see the Mapping >
LocationDisplay sample in the ArcGIS Runtime SDK for .NET samples. See the NmeaParser project on GitHub for an open source
library for communicating with Bluetooth GPS devices.
Related Topics
Navigate the map
Maps and layers
The following code sample uses the MessageLayer to process a message and display the corresponding graphic:
// create a dictionary to hold message properties
var messageProps = new Dictionary<string, string>();
Related Topics
Symbols and renderers
Create a scene
In ArcGIS, a three-dimensional map is known as a Scene. Introduced in ArcGIS Runtime SDK for .NET at version 10.2.6, scenes allow
you to experience a more realistic view of the world by adding the third dimension to your data. Viewing data in 3D gives you new
perspectives and can provide insights that would not be readily apparent from a 2D map of the same data.
Define a scene
ArcGIS Runtime SDK for .NET provides the SceneView and Scene controls for visualizing your data in three dimensions. These controls
are very similar to the MapView and Map controls used for displaying two dimensional maps. Just as a map view contains a single map, a
scene view contains a single scene. Like a map, a scene contains a collection of layers to display. In addition to layers that are unique for
3D mapping, a scene can contain the same types of layers you add to a map.
A scene view can contain only one scene at a time, however, multiple scene objects can be created and swapped out dynamically in the
scene view as the application is running.
The following XAML displays the same layer in three dimensions using a SceneView and Scene.
<esri:SceneView x:Name="MySceneView">
<esri:Scene>
<layers:ArcGISTiledMapServiceLayer ID="AGOLayer"
ServiceUri="http://services.arcgisonline.com/arcgis/rest/services/World_Street_Map/MapServer" />
</esri:Scene>
</esri:SceneView>
In this basic example, all you have to do to view the layer in three dimensions is change the Map element to Scene and the MapView
element to SceneView in your XAML.
HFA
HRE
IMG
JPEG
JPEG 2000
NITF
PNG
RPF
SRTM1, 2
You can define your scene's surface using any combination of local and online elevation sources. The following example defines a surface
by creating an ElevationSourceCollection consisting of both online and local sources.
<esri:SceneView x:Name="MySceneView">
<esri:Scene>
<esri:Scene.Surface>
<esri:ElevationSourceCollection>
<esri:FileElevationSource x:Name="MyLocalElevationSource">
<esri:FilenameCollection>
<x:String>D:\data\DTED\HI_Hawaii\DTED\DTED2\w155\n19.dt2</x:String>
<x:String>D:\data\DTED\HI_Hawaii\DTED\DTED2\w156\n18.dt2</x:String>
<x:String>D:\data\DTED\HI_Hawaii\DTED\DTED2\w156\n19.dt2</x:String>
<x:String>D:\data\DTED\HI_Hawaii\DTED\DTED2\w156\n20.dt2</x:String>
</esri:FilenameCollection>
</esri:FileElevationSource>
<esri:ServiceElevationSource ServiceUri="http://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer"/>
</esri:ElevationSourceCollection>
</esri:Scene.Surface>
<layers:ArcGISTiledMapServiceLayer ID="AGOLayer"
ServiceUri="http://services.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer" />
</esri:Scene>
</esri:SceneView>
Note: An individual ElevationSource can be enabled or disabled by setting its IsEnabled property. This gives
you the ability to change the current surface used by your scene when your app is running.
Once a surface is in place, graphics layers and overlays can define how the surface is used to draw grapics. A GraphicsLayer or
GraphicsOverlay can set the SurfacePlacement property of its associated LayerSceneProperties to one of the following values:
DrapedGraphics draw directly on the surface, like laying a sheet over the topography defined by the surface. The resulting z-
values on the draped layer are equal to the z-values of the underlying surface. Drawing streets that follow the underlying terrain is
an example of draped placement.
AbsoluteGraphics draw using z-values defined for the layer. The z-values are independent of values provided by the surface.
Drawing aircraft at their current altitude above sea level is an example of an absolute placement.
RelativeGraphics draw using z-values defined for the layer using the surface z-value as the baseline. In other words, the z-
values for the graphics are added to the z-values defined for the surface. Displaying the height of a power line network above the
terrain is an example of using relative placement.
The following example shows XAML that sets the SurfacePlacement property of a graphics layer to Draped.
<layers:GraphicsLayer ID="DrapedGraphics">
<layers:GraphicsLayer.SceneProperties>
<layers:LayerSceneProperties SurfacePlacement="Draped"/>
</layers:GraphicsLayer.SceneProperties>
</layers:GraphicsLayer>
if(double.IsNaN(elevation))
{
elevation = e.Location.Z;
}
// ... do something with the elevation value here ...
}
See the Scene navigationtopic for information about mouse, touch, and keyboard navigation functionality that is built into the scene view
control. Set camera position programmatically in the same topic has information and examples for defining the scene display with code
and for synchronizing the display between a map and scene view in your app.
Properties
IsShadowsEnabledWhether or not shadows appear on the scene.
ElevationExaggerationThe factor by which elevation values are exaggerated.
Note: Elevation exaggeration is not applied only to the surface, but to the scene as a whole. Graphics
draped on the scene surface will follow the new exaggerated surface, while graphics displayed in
relative or absolute modes will be positioned by multiplying their z-values by the exaggeration factor.
LightPointThe position of the light source (sun, in other words) for the scene (x, y, z). For a realistic sun position based on the
time, use the SetSunTime method. Use the LightPoint property to set the light position to a specific location (which may or
may not reflect a realistic position for the sun).
AmbientLightThe color of ambient light in the scene when shadows are enabled.
Methods
SetSunTimeSets the location of the sun in the sky (and resulting shadows on the scene, if enabled) using a DateTime object.
LocationToScreenConverts a point in geographic coordinates to screen coordinates (measured from the upper left corner of
the scene). Optionally, you can return a ScreenPointVisibility value to describe the point's visibility (Visible,
HiddenByEarth, HiddenByElevation, NotOnScreen).
ScreenToLocationConverts a point in display coordinates to geographic coordinates.
Related Topics
Add layers to your scene
Display graphics in a scene
Navigate a scene
Navigate a scene
In many ways, navigating a scene is similar to navigating a map. Both offer the ability to zoom in and out, and to pan the display. The
three-dimensional display of a scene, however, adds some additional options for visualization. To fully understand navigating the display
in three dimensions, you must understand the fundamentals of how a scene displays.
Fundamentals of 3D navigation
To display data in three dimensions, a scene uses the concept of a camera and a target. The camera represents the location of the
observer in three-dimensional space (x,y,z) and the target is the location on the 3D surface that intersects the camera's line of sight. You
can think of viewing a map in these same terms, where the camera is always perpendicular to the target on the two-dimensional surface.
Bringing the camera closer has the effect of zooming in. Moving it further away zooms out. Likewise, panning moves the center of the map
(the target) to a new location.
In addition to moving nearer or further relative to the target, in three-dimensional visualization, you can change the pitch, heading, and
elevation of the camera (observer) to produce a different perspective of the data.
The following characteristics of the camera are taken into account when displaying a three-dimensional scene.
Location (target) on the surface (x,y coordinates)
Heading from the camera location (on the surface) to the target
Elevation (z-coordinate)
Pitch (tilt) relative to the surface
Navigation operations
Navigation operations in a scene work by modifying one or several of the camera characteristics described previously.
Zoom in and outMoves the camera towards or away from the target along the line of sight. This also moves the camera location
closer to the target along the direction of the heading while decreasing the elevation.
PanMoves the camera to a new x,y location (without changing other properties).
PitchChanges the angle of the camera relative to the surface.
RotateChanges the camera location on the surface (x,y) and the camera heading without moving the target (or changing pitch or
elevation). In other words, the target is the center point around which the entire scene rotates.
Note: Changing the heading property of the camera is like turning it in a horizontal plane (that is, left or right). It
turns the scene centered on the camera location and therefore changes the location of the target. Rotating
turns the scene while centered on the target, which has the effect of changing the camera heading and x,y
location but not the location of the target. Walking around the Eiffel Tower to view it from various
perspectives is analogous to rotating a scene. By contrast, standing in one place and scanning the Paris
skyline is like changing the heading without moving the camera.
The SceneView control has built-in interactions for mouse, touch, and keyboard that implement these operations for the user.
Built-in navigation
The following table summarizes the built-in navigation capabilities of the SceneView control. See the Navigate the map topic for the
interaction capabilities built into MapView.
Flick
Rotate Hold right button and drag Multiple finger hold and twist
The MouseWheelZoomInDirection property allows you to define the mouse wheel scroll direction used for zooming in to (and out of)
the scene and ZoomFactor sets the factor for zooming, as shown in the following example.
// create a new SceneInteractionOptions
var interactionOptions = new SceneInteractionOptions();
// set the mouse wheel direction for zooming in the scene
interactionOptions.MouseWheelZoomInDirection = MouseWheelDirection.Backward;
// set the factor used for default zoom operations (mouse wheel click, key press, etc.)
interactionOptions.ZoomFactor = 10;
// apply the interaction options to the scene view
MySceneView.InteractionOptions = interactionOptions;
The FlickInertia property allows you to specify an inertia factor when panning the scene with a flick gesture, as shown in the
following example. A factor of 0, which is the default value, disables inertia when panning.
// create a new SceneInteractionOptions
var interactionOptions = new SceneInteractionOptions();
// set the inertia factor when panning (flicking) the scene
interactionOptions.FlickInertia = 10;
Tip: If the desired navigation gesture is not initially recognized, remove your fingers and replace
them on the display.
Keyboard shortcuts
The SceneView control provides built-in support for navigating a scene using keyboard input. The following list describes the keys that
can be used to execute navigation operations.
Arrow keys (up, down, right, left)Pan (north, south, east, west)
Q + mouseFly mode (combination pan and rotate based on mouse position)
A, DHeading
W, SChange pitch
U, JElevation
PMoves pitch to perpendicular to the surface
NMoves the heading to north
InsertZooms to initial extent
Pan interactively
Most often, when panning a scene using touch or mouse, the location you start panning from will be anchored to the pointer as you drag.
You will find certain contexts, however, where the pan interaction behaves significantly differently. The exceptions to the usual pan
behavior described in this section are built into the scene view to ensure a better experience for certain types of interaction.
Move the pointer (the mouse or your finger, in other words) and this location follows the pointer as you pan.
Continue to pan in a single direction until the pointer crosses the horizon (into space, in other words). As the pointer nears the horizon,
the original location is unanchored from the pointer and the scene now pans at a consistent rate as you move. This prevents the scene
from panning too quickly or erratically near the horizon, where a short distance on the display represents a large distance on the scene
(a small scale, in other words).
Bring the pointer back within the scene (inside the horizon), and the pointer will again anchor to a location on the map (but probably not
the original one).
Elevate or pan
If you click or tap a location on the surface that is within a tolerance of the horizon and drag the pointer forward or back, the camera
increases or decreases elevation rather than panning. Moving the pointer left and right, however, pans with the pointer anchored to the
point. Clicks outside of the horizon area will start a pan operation as described in the section above. The following images illustrate
clicking near the horizon and dragging down to elevate the camera.
Note: The tolerance for clicks near the horizon (instantiating an elevate operation, in other words) is defined
using a 5 angle from the horizon towards the camera target. The ability to elevate the camera from a click
near the horizon is not available when the scene is displayed at a relatively small scale (displaying a larger
area, in other words).
The following methods are available to manipulate the characteristics of a Camera. These are useful for defining a new camera relative to
an existing one. Each of these methods returns a new Camera object that can then be applied to the scene using
SceneView.SetViewAsync.
Elevateapply a delta elevation value to the current z-coordinate value.
MoveForwardmove the camera a delta distance (meters) along the line of sight to the target.
MoveTowardmove the camera a specified distance (meters) towards a specified location (point).
Rotateapply a delta heading and delta pitch relative to the current camera.
RotateAroundapply a delta heading and delta pitch relative to a specified location (point).
SetHeadingspecify an absolute heading value (angle from true north).
SetLocationspecify an absolute location (point).
SetPitchspecify an absolute pitch angle.
ZoomTowardzoom the camera towards or away from a specified location (point) at a specified zoom factor.
A Camera can also be created new, as shown in the following example. The constructor allows you to define values for location (x, y, z
coordinates), heading, and pitch.
var camera = new Esri.ArcGISRuntime.Controls.Camera(centerLatitude, centerLongitude, headingDegrees, pitchAngle);
await MySceneView.SetViewAsync(camera, animationVelocity, showLiftOff);
Tip: You can animate the updated camera as it is applied to the scene using an appropriate overload of
SceneView.SetViewAsync.
// apply the view point to a scene view and map view (animate the change in the scene view)
await MySceneView.SetViewAsync(viewPoint, animationDuration, true);
await MyMapView.SetViewAsync(viewPoint);
Navigation events
The SceneView control raises CameraChanged and NavigationCompleted events. In general, NavigationCompleted is the
best event to handle if you want to respond each time the user navigates the scene. The CameraChanged event is much more granular
and may fire several times for a single navigation operation.
The following code handles the NavigationCompleted event to get information about the current camera position.
private async void MySceneView_NavigationCompleted(object sender, EventArgs e)
{
// get the camera used to render the current scene
var camera = MySceneView.Camera;
// get info about the camera
var latitude = camera.Location.Y;
var longitude = camera.Location.X;
var pitch = camera.Pitch;
var heading = camera.Heading;
// ... code here to update the UI with camera info ...
Related Topics
Create a scene
Add layers to your scene
Display graphics in a scene
Note: Some layers, such as a SceneLayer, are exclusive to a Scene and cannot be
added to a Map.
Layer scene properties
All layers supported for display in a (2D) map can also be added to a (3D) scene. The GraphicsLayer and GraphicsOverlay classes
define a SceneProperties property to define behavior when rendering the layer in a scene. The property is set with a
LayerSceneProperties object that defines the SurfacePlacement setting to control how the layer displays relative to the scene's
elevation source (if one is defined).
See the Create a scene topic for more information and an example of defining an elevation source for a scene.
The LayerSceneProperties.SurfacePlacement property can be set to one of the following values:
DrapedGraphics draw directly on the surface, like laying a sheet over the topography defined by the surface. The resulting z-
values on the draped layer are equal to the z-values of the underlying surface. Drawing streets that follow the underlying terrain is
an example of draped placement.
AbsoluteGraphics draw using z-values defined for the layer. The z-values are independent of values provided by the surface.
Drawing aircraft at their current altitude above sea level is an example of an absolute placement.
RelativeGraphics draw using z-values defined for the layer using the surface z-value as the baseline. In other words, the z-
values for the graphics are added to the z-values defined for the surface. Displaying the height of a power line network above the
terrain is an example of using relative placement.
The following example shows XAML that sets the SurfacePlacement property of a graphics layer to Draped.
<layers:GraphicsLayer ID="DrapedGraphics">
<layers:GraphicsLayer.SceneProperties>
<layers:LayerSceneProperties SurfacePlacement="Draped"/>
</layers:GraphicsLayer.SceneProperties>
</layers:GraphicsLayer>
// create a graphics layer to show the graphics using absolute placement using the z values
var graphicsLayer = new GraphicsLayer();
graphicsLayer.SceneProperties.SurfacePlacement = SurfacePlacement.Absolute;
3D layers
In addition to the familiar layers you may have used in your 2-dimensional maps, such as ArcGISTiledMapServiceLayer,
GraphicsLayer, and so on, you can also add specialized 3D layers to your scene. With the 10.3 release of ArcGIS for Server, scene
services are now available for delivering 3D content. These services support publishing and consuming large volumes of multipatch
features, such as buildings for entire cityscapes. Scene services are created by publishing a scene using ArcGIS Pro.
These new services can be consumed in your ArcGIS Runtime SDK for .NET app. The following example uses a SceneLayer to show a
scene service of buildings in Montreal, Canada.
<esri:SceneView x:Name="MySceneView" AmbientLight="Gray">
<esri:Scene>
<esri:Scene.Surface>
<esri:ServiceElevationSource ServiceUri="http://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer"
IsEnabled="True" ID="elevationLayer" />
</esri:Scene.Surface>
<layers:ArcGISTiledMapServiceLayer ID="AGOLayer"
ServiceUri="http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer" />
<layers:SceneLayer ID="MontrealBuildings"
ServiceUri="http://scene.arcgis.com/arcgis/rest/services/Hosted/Buildings_Montreal/SceneServer/layers/0" />
</esri:Scene>
</esri:SceneView>
KML layers
Keyhole Markup Language (KML) is an XML format for describing geographic features for visualization in two dimensional maps or three
dimensional scenes. KML files use a .kml extension for plain KML text files or .kmz for compressed files. In your ArcGIS Runtime apps,
you can use the KmlLayer to read and display geographic information from a .kml or .kmz file, which can be stored locally or accessed
from an online source.
The following example shows XAML that defines a scene with a KML layer showing recent earthquakes.
<esri:SceneView x:Name="MySceneView">
<esri:Scene>
<esri:Scene.Surface>
<esri:ServiceElevationSource
ServiceUri="http://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer" />
</esri:Scene.Surface>
<layers:ArcGISTiledMapServiceLayer ID="AGOLayer"
ServiceUri="http://services.arcgisonline.com/arcgis/rest/services/World_Street_Map/MapServer" />
<layers:KmlLayer ID="QuakesKml"
SourceUri="http://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/1.0_week_age_link.kml">
</layers:KmlLayer>
</esri:Scene>
</esri:SceneView>
For more information, see the KML layers description in the Layer Types topic.
Layer initialization
Layers are initialized asynchronously when added to the scene. Attempting to access certain properties or operations before layers are
initialized may throw an exception. For example, getting the spatial reference or camera position of the scene, or the name or extent of a
layer. You can handle the LayerLoaded event on the SceneView to know if (and when) each layer loads successfully into the scene.
The following example handles the LayerLoaded event and checks for a successful load of the streets layer (using its ID). Upon a
successful load of the layer, the camera position is set for the scene.
private void MySceneView_LayerLoaded(object sender, LayerLoadedEventArgs e)
{
if (e.LoadError == null && e.Layer.ID == "StreetMapLayer")
{
var mapPoint = new MapPoint(-122.40, 37.78, 210.0);
MySceneView.SetViewAsync(new Esri.ArcGISRuntime.Controls.Camera(mapPoint, 340.0, 75.0), 1, true);
}
}
You can also await the LayersLoadedAsync method to get the status of all layers after the scene view attempts to load them.
The following code example uses the LayersLoadedAsync method to await the loading of all the scene's layers. After loading is
attempted for all layers, the InitializationException property populates for layers that encountered an exception while loading
(otherwise, the property contains null). The following code would be called in the constructor for the page.
private async Task TryLoadLayers()
{
var builder = new StringBuilder();
await this.MySceneView.LayersLoadedAsync();
foreach (var layer in MySceneView.Scene.Layers)
{
if (layer.InitializationException != null)
{
builder.AppendLine(layer.InitializationException.Message);
}
}
// report layer initialization exception messages here ...
}
Related Topics
Display graphics in a scene
Navigate a scene
Create a scene
Graphics overlays
Graphics overlays are containers for your graphics and will display above all layers in the scene. The GraphicsOverlay class provides
methods for adding or removing graphics from the collection, as well as controlling how graphics are rendered. Graphics to display in a
scene should be created with geometries in {x, y, z} coordinates of longitude (degrees), latitude (degrees), and elevation (meters). In
addition, an appropriate ElevationMode should be set on the graphics overlay.
Elevation modes
The elevation mode controls how each graphic's z-value is applied when displayed in a scene.
DrapedThe elevation set on any point, line, or polygon graphic is ignored. Graphics appear draped on the surface of the
globe, like a sheet.
AbsoluteThis is the default mode. The elevation values (z-values) of each graphic or feature are calculated from sea level,
regardless of the terrain elevation at the x,y locations of the graphics.
RelativeThe elevation values (z-values) of each graphic or feature are calculated relative to the terrain elevation at the x,y
locations of the graphics.
// create a new graphic; assign the point and the symbol in the constructor
var graphic = new Graphic(newPoint, xMarkerSym);
// get a graphics overlay in the scene view and add the graphic
var overlay = MySceneView.GraphicsOverlays["MyGraphicsOverlay"];
overlay.Graphics.Add(graphic);
Rather than creating a symbol for each graphic individually, you can define a renderer for the containing GraphicsOverlay or
GraphicsLayer. All graphics added to the container (overlay or layer) can use the symbol defined by the renderer.
Renderers
A renderer determines how features in a layer or graphics in an overlay are drawn. A renderer can use a single symbol to render all
features, or it may contain logic to render features according to one or more attribute values. A UniqueValueRenderer, for example,
uses a different symbol for each unique attribute value (or combination of values). A ClassBreaksRenderer symbolizes features
according to defined ranges of numeric values, such as classes of population. All renderers are found in the
Esri.ArcGISRuntime.Symbology namespace, and can be used for rendering in a map or scene. See the Symbols and renderers
topic for more information about renderers.
The following example shows XAML to define a simple renderer for a graphics layer.
<layer:GraphicsLayer ID="GraphicsLayer" >
<symb:GraphicsLayer.Renderer>
<symb:SimpleRenderer>
<symb:SimpleRenderer.Symbol>
<symb:SphereMarkerSymbol Color="#FFFF99" Radius="1000" AnchorPosition="Top" />
</symb:SimpleRenderer.Symbol>
</symb:SimpleRenderer>
</symb:GraphicsLayer.Renderer>
</layer:GraphicsLayer>
Note: A graphic's Symbol property takes precedence over symbols in a renderer. Only graphics that do not have
a symbol explicitly defined uses the symbol in the graphics overlay's renderer. This allows you to override
the symbols in a renderer for a particular graphic if needed.
The Renderer base class defines a SceneProperties property that controls aspects of rendering for scene features. It contains
ExtrusionExpression and ExtrusionMode properties to define how heights for features should be calculated for display. In the
following example, the renderer extrudes features by multiplying the value in the Floors attribute by three.
// extrude features to a height (meters) three times the value of the "Floors" attribute
renderer.SceneProperties.ExtrusionExpression = "[Floors] * 3";
renderer.SceneProperties.ExtrusionMode = Maximum;
A scene symbol's orientation can be rotated around any of its three axes: x (pitch), y (roll), or z (heading). Renderers give you the
ability to apply these rotations for each graphic according to an attribute value. You can specify the HeadingExpression,
PitchExpression, and RollExpression using the name of an attribute in square brackets. The following example uses an
attribute to apply a rotation in the z axis (heading) for each graphic in the layer.
// rotate the symbol heading based on the numeric value of the "CurrentHeading" attribute
renderer.SceneProperties.HeadingExpression = "[CurrentHeading]";
Symbols
Graphics in a map or scene can be symbolized using standard (two-dimensional) symbols for the appropriate geometry type:
Esri.ArcGISRuntime.Symbology.MarkerSymbol classes for point geometry, Esri.ArcGISRuntime.Symbology.LineSymbol
for polyline geometry, and Esri.ArcGISRuntime.Symbology.FillSymbol for polygons. The height of features can be extruded
using an attribute value assigned to a renderer for the graphics layer or overlay. Without extrusion, features drawn with 2D symbols
display on the surface of the scene in two dimensions.
Graphics in a scene can also be symbolized using 3D-specific symbols found in the
Esri.ArcGISRuntime.Symbology.SceneSymbology namespace. The following class diagram shows the 3D-specific symbol
classes:
The symbol options appropriate for each geometry type are described below.
Points
To symbolize points in a scene, you can use 3D-specific marker symbols, such as BoxMarkerSymbol, SphereMarkerSymbol,
ConeMarkerSymbol, and so on.
Marker symbols that display as three-dimensional shapes (box, cone, sphere, diamond, or tetrahedron) have a Color property and
properties for defining marker size. The way a marker size is defined varies by type of shape: Radius for a sphere, RadiusTop and
RadiusBottom for a cone, Width, Height, and Depth for a box, and so on.
The following example creates a red SphereMarkerSymbol with a two kilometer radius.
// creates a red sphere with a radius of 2000 meters
var sphereSym = new SphereMarkerSymbol();
sphereSym.Color = Colors.Red;
sphereSym.Radius = 2000;
// create a graphic and apply the sphere symbol
var pointGraphic = new Graphic(someGeoPoint, sphereSym);
// add the graphic to a graphics layer in the scene
var layer = MySceneView.Scene.Layers["GraphicsLayer"] as GraphicsLayer;
layer.Graphics.Add(pointGraphic);
A model symbol is used to provide a realistic three-dimensional visualization to symbolize scene features. Create a
ModelMarkerSymbol using a 3D model file, passing the path to the file and a scale factor to the model symbol constructor. The
supported model file types include Collada (.dae), 3D Max (.3ds), Blender 3d (.blend), and the formats listed in the Open Asset
Import Library (Assimp). Depending on the model file's default orientation, you may have to rotate the symbol to get your model in the
desired orientation.
Some common scene marker symbol types are pictured below in a scene. The symbols are, from left to right, sphere, box, diamond,
cone, and model symbol.
To symbolize points in a scene, in addition to the 3D marker symbols, you can also use the same symbol classes as for point graphics
in a 2D map: SimpleMarkerSymbol, PictureMarkerSymbol, and TextSymbol. These classes are not subclasses of
SceneSymbol.
Note: Although 2D point symbols display in a Scene, scene symbols are not
supported in a Map.
Lines
To symbolize line graphics in a scene, you can either use the 3D-specific TubeLineSymbol or the standard 2D symbols, such as
SimpleLineSymbol. To show the height of features, use a renderer with an extrusion expression defined.
Polygons
To symbolize polygons in a scene, use SimpleFillSymbol, as you would in a map. To show the height of features, use a renderer
with an extrusion expression defined.
Composite symbols
A composite symbol allows you to create a symbol that is composed of several symbols. For 2D and 3D rendering, you can use a
CompositeSymbol to build a symbol from a collection of symbol objects. For example, you may want to overlay several
SimpleMarkerSymbol objects to create a custom symbol (a triangle inside a circle, for example). A composite symbol is also useful
for combining your marker, line, or fill symbol with a text symbol to display a label.
The DistanceCompositeSymbol is a composite symbol that is specific to rendering features in a scene. Like CompositeSymbol, it
allows you to define a symbol from a collection of symbols. In addition, it gives you the ability to assign a visibility range for each symbol
based on the distance of the feature to the current camera position in the scene. Using this symbol, you can show features that are far
from the camera with a simple symbol and those that are nearer with a 3D-specific symbol (such as a model symbol). The 3D-specific
symbols render according to their absolute size in meters and may not be easily visible at large distances. By contrast, a
SimpleMarkerSymbol consistently renders according to screen units and is visible regardless of distance. Simple marker symbols are
also less resource-intensive than 3D marker symbols (especially model symbols), so they should be used whenever appropriate to
make your app more efficient.
The following example creates a 3D composite symbol that renders features with one of three symbols depending on the camera
distance. It also defines a text label that always appears.
DistanceCompositeSymbol compositeSymbol = new DistanceCompositeSymbol();
// ... code here to create new ModelMarkerSymbol, ConeMarkerSymbol, SimpleMarkerSymbol, and TextSymbol ...
// use a model symbol when the camera is within 100,000 meters
var nearSymbolInfo = new DistanceCompositeInfo(modelSymbol, 0, 100000);
compositeSymbol.Infos.Add(nearSymbolInfo);
// use a cone marker symbol for intermediate distances (100,000 to 600,000 meters)
var midSymbolInfo = new DistanceCompositeInfo(coneSymbol, 100000, 600000);
compositeSymbol.Infos.Add(midSymbolInfo);
// use a simple marker symbol for large distances
var farSymbolInfo = new DistanceCompositeInfo(markerSymbol, 600000, 10000000);
compositeSymbol.Infos.Add(farSymbolInfo);
// add a text label to appear at all distances
var textSymbolInfo = new DistanceCompositeInfo(textSym, 0, 10000000);
compositeSymbol.Infos.Add(textSymbolInfo);
HeadingRotates the symbol around its z-axis. For example, change a directional symbol from pointing north, by default, to
pointing east, by setting its heading to 90 (markerSym3D.Heading = 90).
PitchRotates the symbol around its x-axis. For example, change a directional symbol from pointing up along the z-axis, to
pointing parallel to the ground, by setting its pitch to -90 (markerSym3D.Pitch = -90).
RollRotates the symbol around its y-axis. For example, change a symbol from being parallel to the ground to being
perpendicular to the ground by setting its roll to 90 (markerSym3D.Roll = 90).
Related Topics
Navigate a scene
Create a scene
Add layers to your scene
Note: For Identify and Query, you can also include temporal criteria for the
search.
Tasks overview
Searching is implemented using tasks. Specifically, the FindTask, QueryTask, and IdentifyTask classes allow you to tailor your
searches for the type of questions you need to answer. To implement one of these tasks in your code, follow these general steps:
1. Create a new Task object and point it to an appropriate online or local resource (for example, a FeatureService).
2. Specify Task parameters, which are stored as properties of an appropriate parameters object. (for example, FindParameters for
use with a FindTask). Task parameters specify the search criteria as well as the output spatial reference and fields.
3. Execute the task, passing in the parameters object you've defined.
4. Process the results that are returned (summarize values, display graphics, and so on.).
Tip: You can give the user the ability to cancel long-running tasks by providing a CancellationToken when
creating the task.
In addition to the search tasks described here, the ArcGIS Runtime SDK provides a variety of other Task classes. There are tasks for
geocoding addresses, getting driving directions, printing, and more. Although individual tasks provide a range of functionality for use in
your app, they all share the same essential programming pattern described above.
Find features
FindTask provides the ability to return a subset of features based exclusively on attribute criteria. The task will search for a single (text)
value in a specified set of attribute fields within a specified set of layers and return all features that have a matching attribute value.
FindTask can be configured to match the search value exactly, or to match attribute values that simply contain the search string as part
of the attribute value.
For example, the following image shows the result of executing a FindTask to return state, city, or river features that contain the text Red
in either the NAME or CITY_NAME attribute:
The following code illustrates how to return all features in a set of specified service layers that contain a search term in one of the specified
attributes:
// Create a new FindTask, pointing to the map service to search in the constructor
var url =
"http://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer";
var findTask = new FindTask(new Uri(url));
// Create a FindParameters object
var findParameters = new FindParameters();
// Set properties to define the search
//--the layer ids to search
findParameters.LayerIDs.Add(0); // Cities
findParameters.LayerIDs.Add(3); // Counties
findParameters.LayerIDs.Add(2); // States
//--the fields to search
findParameters.SearchFields.Add("name");
findParameters.SearchFields.Add("areaname");
findParameters.SearchFields.Add("state_name");
//--return feature geometry with the results
findParameters.ReturnGeometry = true;
//--the spatial reference for result geometry (match the map's)
findParameters.SpatialReference = MyMapView.SpatialReference;
//--the text to search for and how to evaluate matches
findParameters.SearchText = SearchForTextBox.Text;
findParameters.Contains = true; // false == match exactly
// Asynchronously execute the task; await the result
FindResult findResult = await findTask.ExecuteAsync(findParameters);
var foundCities = 0;
var foundCounties = 0;
var foundStates = 0;
Executing a FindTask returns a collection of result objects, each one indicating which layer, field, and attribute value was matched by
executing the task. Perhaps most importantly, it gives you access to a graphic for the match, which includes all attributes and (if geometry
was requested in the input parameters) the shape and location of the feature that was found.
Geometry for the find results can be returned in a specified spatial reference by specifying the output spatial reference in the parameters
used as input for the task. If a spatial reference is not specified, results will be returned in the spatial reference of the map service being
searched. Most often, you will need the result features in the same spatial reference as your app's map.
Tip: If you will not need to use the geometry of your results (for example, for displaying the located features), you
should indicate that geometry should not be returned by the task (in the task parameters). Excluding the
geometry portion of your results can greatly improve performance, especially if several features (or complex
geometries) are potentially being returned.
Query features
A QueryTask provides the ability to return a subset of features from a single layer based on any combination of attribute, spatial, and
temporal criteria. Rather than searching for a single text value as FindTask does, a QueryTask can take a compound expression that
uses several attribute fields, data types, and operators (for example, POP > 1000000 AND NAME LIKE 'San%'). Unlike FindTask,
QueryTask does not let you specify a set of layers to search in a single operation but gives you much more control over the criteria used
to perform a search.
Note: A query does not require that all types of criteria be defined (attribute, spatial, and temporal). Leaving spatial
and temporal filters undefined, for example, means that the search will not be restricted using those criteria
(that is, the entire spatial and temporal extent will be evaluated).
The following code example queries the Police layer (index = 1) in the RedlandsEmergencyVehicles service using attribute, spatial,
and temporal criteria. A TimeExtent is passed into the constructor for the QueryTask that identifies a period from five minutes ago to
the present time. The attribute criteria is applied with an expression to find all unmarked vehicles (TYPE = 2) that are currently available
(STATUS = 1) or any vehicle that is traveling at or below 10 miles per hour (SPEED <= 10). The map's extent is used as the spatial
criteria to ensure that only features in the current extent are considered in the query.
Code to query a feature service layer and display the results as graphics in the map.
// Create a new QueryTask, indicate the map service to query in the constructor
var url =
"http://sampleserver5.arcgisonline.com/arcgis/rest/services/RedlandsEmergencyVehicles/FeatureServer/1";
var queryTask = new QueryTask(new Uri(url));
// Create a new Query object to define parameters; pass in a time extent
var timeWindow = new Esri.ArcGISRuntime.Data.TimeExtent
(DateTime.Now.Subtract(new TimeSpan(0, 5, 0, 0)), DateTime.Now); // 5 minutes ago to present
var queryParams = new Esri.ArcGISRuntime.Tasks.Query.Query(timeWindow);
// Set properties of the Query
//--attribute criteria (where expression)
queryParams.Where = "(TYPE = 2 AND STATUS = 1) OR (SPEED <= 10)";
//--spatial criterion; default relationship is "intersects"
queryParams.Geometry = MyMapView.Extent;
//--return feature geometry with the results
queryParams.ReturnGeometry = true;
//--output spatial reference
queryParams.OutSpatialReference = MyMapView.SpatialReference;
// Execute the task and await the result
QueryResult queryResult = await queryTask.ExecuteAsync(queryParams);
// Get the list of features (graphics) from the result
var resultFeatures = queryResult.FeatureSet.Features;
Query criteria can be specified using any combination of attribute, spatial, and temporal criteria. Attribute criteria is defined using a SQL
expression in the form "attribute operator value" (for example, "POPULATION < 2000000"). Several conditions can also be
connected using AND or OR to produce compound attribute expressions: "(POPULATION < 2000000 AND (REGION = 'Pacific'
OR REGION = 'Midwest'))".
Spatial criteria for a query requires two pieces of information: a Geometry object whose relationship to features in the query layer will be
evaluated, and the type of relationship to evaluate. The available spatial relationships are as follows:
IntersectsPart of an input feature is contained in the query geometry
ContainsPart or all of an input feature is contained within the query geometry
CrossesAn input feature crosses the query geometry
EnvelopeIntersectsThe envelope of an input feature intersects the envelope of the query geometry
OverlapsAn input feature overlaps the query geometry
TouchesAn input feature touches the border of the query geometry
WithinAn input feature is completely enclosed by the query geometry
Temporal criteria are defined using a TimeExtent, which can define a single point in time or a time range.
Tip: To return all features with a query, you can use an expression that is always true, such as "1=1", and leave
the spatial and temporal criteria undefined.
Similar to the FindTask, a QueryTask is generally used to return what is essentially a collection of result objects. The individual results
(graphics) can be accessed from the result in order to display them in the map or to work with their attribute values. Depending on the
needs for your app, you can simply return a list of ObjectIDs (rather than the actual features) that meet the query criteria. Similarly, you
can return just the count of resulting features. Returning the count or a list of IDs will usually perform much better than returning a set of
features.
You can also use a QueryTask to find features in a related dataset for a particular layer. You can pass in the same types of input for the
task parameters when searching related records (such as query criteria, output spatial reference, and whether to include geometry), but
you also need to indicate the relationship ID for the related dataset. This ID can be found by consulting the metadata for the layer in the
service (REST page).
Geometry for the query results can be returned in a specified spatial reference by specifying the output spatial reference in the parameters
used as input for the task. If a spatial reference is not specified, results will be returned in the spatial reference of the map service being
searched. Most often, you will need the result features in the same spatial reference as your app's map.
Tip: If you will not need to use the geometry of your results (for example, for displaying the located features), you
should indicate that geometry should not be returned by the task (in the task parameters). Excluding the
geometry portion of your results can greatly improve performance, especially if several features (or complex
geometries) are potentially being returned.
Before attempting a query, you can check a geodatabase feature table to see if it supports queries. If a query on a local data table is
successful, it will return a collection of results that can be used to access feature information such as attributes and geometry in order to
display your results. In addition to querying a local table with attribute and/or spatial criteria, you can also pass in a list of object IDs to
return the corresponding features.
The following code example illustrates how to open a local geodatabase, access a particular feature table, and execute an attribute
query to get some results:
// Specify a path to a local geodatabase (downloaded from a feature service, e.g.)
var path = System.IO.Path.Combine(@"C:\Temp\Cache", "WildfiresLocal");
Identify features
An identify operation is a user-driven operation typically involving a single click on the map and the retrieval of information about features
hit by that clicked point from any layer in the map. In the ArcGIS Runtime SDK for .NET, you can use the IdentifyTask to search the
layers in both local and online data for features that intersect an input geometry. Once the matching features are returned, you can display
their geometries and attributes in your app.
Define parameters to control how you want the identify to operate. The following are some basic guidelines:
Information about the map is required for an IdentifyTask to correctly evaluate the relationship between features in the service
and the input geometry. These include the map dimensions (width and height, in pixels), the current map extent, and the screen
resolution (dots per inchthe default value is 96).
Identify operates by intersecting a geometry with the features in one or more layers. Provide the intersection geometry using a
Point, Polyline, Polygon, Envelope, or Multipoint.
Tip: To control the spatial relationship evaluated in the identify (a relationship other than intersection), use
a QueryTask instead.
Specify a tolerance to control the distance (in pixels) from your geometry within which the intersection will be performed.
Geometry for the IdentifyTask results can be returned in a specified spatial reference by setting the output spatial reference.
This value also indicates which spatial reference is being used for the input geometry and input map extent values. If it is not
specified, the spatial reference of the map service being searched will be assumed. In general, you should set this property using
the spatial reference of your map.
An Identify operation has the potential to retrieve a lot of information, especially if there are several layers involved. To improve
performance and to make your Identify operation more efficient, you can specify the layers to include in your search. You can
specify the layers, by ID, that take part in the Identify task. Alternatively, you can identify only the visible layers, only the top most
(visible) layer, or all layers (regardless of visibility).
The results of the Identify task are returned as a collection of result objects. Each item in the collection represents the identify result for a
layer included in the operation. You can process the contents of the layer results to get to the individual features (geometry and attributes)
returned by the operation.
The following code example uses an IdentifyTask in response to a click on the map to display information about a feature clicked by
the user:
// When the mouse button is released on the Map, use Identify to get info
private async void MyMapView_MouseUp(object sender, MouseButtonEventArgs e)
{
var screenPoint = e.GetPosition(MyMapView);
topLayerFeature.Symbol = symbol;
// Display the feature as a graphic on the map
var resultLayer = MyMap.Layers["IdResultGraphics"] as GraphicsLayer;
resultLayer.Graphics.Clear();
resultLayer.Graphics.Add(topLayerFeature);
// Display the attributes in a data grid on the page
this.ResultsDataGrid.ItemsSource = topLayerFeature.Attributes;
}
}
if (queryResult != null)
{
// Process results ...
}
// Execute the task with the cancellation token; await the result
QueryResult queryResult = null;
Task<QueryResult> task = queryTask.ExecuteAsync(queryParams, token);
try
{
queryResult = await task;
}
catch (System.Threading.Tasks.TaskCanceledException exp)
{
// ... handle cancel here ...
}
// Get the graphics layer in the map; set the source with the result features
var graphicsLayer = MyMap.Layers["Graphics"] as GraphicsLayer;
graphicsLayer.GraphicsSource = resultFeatures;
}
Cancelling the task will cause a System.Threading.Tasks.TaskCanceledException to be thrown. When allowing the user to
cancel a task, you'll need to anticipate and handle these exceptions gracefully in your code.
Related Topics
Features and graphics
Search for places
Search for coordinates
Geocoding overview
Address geocoding (or geocoding) is the process of using information contained in an address to interpolate a corresponding location on
the map. An address may define a precise street location, such as "380 New York Street, Redlands CA 92373"; may provide only a
general location, such as a city name or postal code; or may be a familiar place name or landmark, such as "Ayers Rock".
Using a reference data source, referred to as a locator, ArcGIS is able to find map locations by matching an input address with feature
attributes. The number and accuracy of the geocoded results (often called matches or candidates) may vary depending on the specificity
and quality of the input address provided. The address "New York", for example, is likely to return a match for the state of New York, the
city of New York, and perhaps several streets or points of interest that share that name. Geocoded locations are always points. If a match
is made with a polygon (a state or postal code, for example), the match location represents the center of that area.
Additional geocoding inputs can improve the relevance of results by restricting the search to a given area or finding matches that are near
a reference location. This allows you to find results for a specified country, map extent, or near the user's current or anticipated location. A
general search like "restaurant", for example, is unlikely to return useful candidates unless it is restricted to a specific area.
When several candidates are returned for an address, they will be sorted by the quality of the match. This means it is generally safe to
assume that the first candidate in the results represents the best match. Sometimes, however, you might want to examine a set of top
candidates to determine the most appropriate match. Address candidates can contain the level at which they were matched (house, street,
postal code, etc.) and the interpolated address created by the locator. Both of these might help you determine the best match or perhaps
find problems in the original address input. If geocoding used a reference location, a distance attribute can help you find the closest
candidate.
Caution: The score attribute, an integer value ranging from 0 to 100, provides an estimate of relative match accuracy
within a single locator. If you are using a composite locator (such as the ArcGIS World Geocoding Service),
these values will represent the score within a locator for a specific level, but not an overall evaluation of the
match. A score of 100 for a postal code match is not necessarily a more precise result, for example, than a
score of 90 at the house level.
Addresses
Addresses are fundamental for geocoding and have some specific characteristics. An address is composed of one or more address
elements: individual components of the address, such as house number, street name, street type, and postal code. Address elements
help in the geocoding search, pinpointing an address to a particular location. Addresses come in various styles and formats, including
street address, a place name, or a location that is identified by a code. A common address format used in the United States consists of
the following series of address elements: house number, prefix direction, prefix type, street name, street type, suffix direction, and zone
information (such as city, state, and ZIP Code). Globally, addresses are represented in a variety of formats. However, while all these
addresses differ to some degree, some things remain consistent. Each address consists of one or more address elements presented in
a particular address format recognized by those in the region.
When geocoding, you can pass in individual components of an address or provide all information as a single string to be parsed.
Defining each component of an address gives you more control but may require that you either parse the components before passing
them to the locator or provide additional UI controls for your user to enter each piece of information.
When geocoding, the type of information expected in an input address is determined by the address style configured by the locator
you're using. Some of the common address component field names for the ArcGIS World Geocoding Service
(http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer) are listed below as an example of the type of input that may be
expected. See Multiple input field geocoding for more details.
AddressHouse number and street
NeighborhoodSubdivision of a city (not used for US addresses)
CityCity or municipality
SubregionAdministrative region, such as a county or province (not used for US or Mexico addresses)
RegionLargest administrative boundary associated with the address (state name in the US)
PostalPostal code
Locators
The fundamental logic for geocoding is built into the locator and does not come from your ArcGIS Runtime SDK code. The locator
(created using ArcGIS for Desktop) is the major component in the geocoding process and contains all the data necessary to perform
address matching. A locator is created based on a specific address locator style, which dictates what type of address input is expected
and how matching will be carried out. The following table lists some of the common address styles, the type of matching that it enables,
and an example of input address values:
Note: This is not a complete list of the available address styles. For a more complete description, see Commonly
used address locator styles in the ArcGIS for Desktop help.
Once created, an address locator contains a set of geocoding properties (preferences), a snapshot of the address attributes in the
reference dataset, and the queries for performing a geocoding search. The address locator also contains a set of address parsing and
matching rules that directs the geocoding engine to perform address standardization and matching.
A locator can be stored locally (as a *.loc file) or can be published as a locator service using ArcGIS for Server. To perform geocoding,
you need to access either an online locator or one available locally on the device. Using ArcGIS Runtime SDK, you can connect to a
variety of online locators published and hosted by Esri, including address locators for Europe and North America, a street locator for the
United States, and a world places locator. These services allow you to begin geocoding with online data right away without having to
create and configure an address locator yourself. Locators can be created and configured with local data using ArcGIS for Desktop as
the authoring environment. See the ArcGIS help topic Creating an address locator for detailed information.
Results
Geocoding results for a particular address are referred to as candidates. Depending on how specific and complete the input address is,
you may get several candidates from a geocode operation. Geocoding results are ordered by quality of the match, so the first candidate
is generally the best. Additional candidate information can be obtained by specifying supplemental output fields to include in the results.
The following table describes a few of the available fields you can include from the world geocoding service. This is only a
representative list of fields. For a complete list, see the Output fields topic in the ArcGIS REST API documentation.
Note: The fields provided may vary between locators. See the Get locator info section of this topic for
information about querying a locator for its available result attributes.
Distance The distance (meters) from the candidate to a specified location. The reference location needs to be specified as a parameter
before executing the task.
Rank A number indicating the importance of each candidate relative to others in the results. Rank is generally used to help distinguish
ambiguous place names using population as the criterion. A search for Las Vegas, for example, may return Las Vegas,
NV as the top ranked match (1) and Las Vegas, NM as a lower rank based on the relative population of those cities. If a
reference location and distance parameters have been set for a find operation, distance from the reference location will be used to
rank candidates.
Tip: You can give the user the ability to cancel long-running tasks by providing a CancellationToken when
creating the task.
In addition to the locator tasks described in this topic, ArcGIS Runtime SDK provides a variety of other Task classes. There are tasks for
querying features by location or attributes, getting driving directions, printing, and more. Although individual tasks provide a range of
functionality for use in your app, they all share the same essential programming pattern described above.
Geocode an address
To geocode an address, call the GeocodeAsync method on either an OnlineLocatorTask or a LocalLocatorTask object. You
need to pass in a Dictionary<string, string> object containing address values, a List<string> with the desired output fields,
and a CancellationToken. If you do not want to allow your user to cancel the request, you can pass in a new cancellation token, as
shown in the following example. Optionally, you can pass in a SpatialReference object to define the desired output spatial reference
for the results.
The address input is a dictionary of address values. The key for each value indicates the name of the address component for the
corresponding value. To set the individual components for "380 New York Street Redlands CA 92373", for example, your code might be
similar to the following:
var address = new Dictionary<string, string>();
address.Add("Address", "380 New York Street");
address.Add("City", "Redlands");
address.Add("Region", "CA");
address.Add("Postal", "92373");
You can also define the address as a single input by setting the single line address value. In that case, the address string will be parsed
into the appropriate components by the locator.
var info = await locatorTask.GetInfoAsync();
var address = new Dictionary<string, string>();
address.Add(info.SingleLineAddressField.FieldName, "380 New York Street Redlands CA 92373");
Tip: The GetInfoAsync method on the locator can be used to determine the name to use for the single line
address input field, as shown in the preceding example.
The following example matches an address with an online locator for Tokyo using the Japanese addressing system. All the logic
required to match addresses is stored with the locator and its reference data. To modify this code to match an address in the US, you
simply change the URI to a locator service that uses US reference data and the US address rules.
// create a new online locator task ("Tokyo residence level locator")
var uri = new Uri("http://sampleserver6.arcgisonline.com/arcgis/rest/services/Locators/????????????/GeocodeServer");
// get info about the locator (will need the name of the single address input field)
var info = await locator.GetInfoAsync();
// store the name of the single address input field
var singleAddressFieldName = info.SingleLineAddressField.FieldName;
// start the geocode task: pass in the address, out candidate fields, out spatial reference, and an empty cancellation token
var task = locator.GeocodeAsync(address, candidateFields, MyMapView.SpatialReference, new System.Threading.CancellationToken());
IList<LocatorGeocodeResult> results = null;
try
{
// await the results of the task
results = await task;
Find places
The OnlineLocatorTask provides a FindAsync method that allows you to quickly search the ArcGIS World Geocoding Service
(http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer) for a place name or address. Using Find rather than Geocode
allows you to restrict your search to a specified country or extent, to search for broad categories of locations (coffee shops, for
example), and gives you the ability to prefer candidates that are closer to a specified location (the user's current position, for example).
You can even provide the user with phone numbers and URLs for candidate locations, as well as the distance from a reference location.
The FindAsync method takes a single-line address value as input and supports finding the following types of locations:
Street addresses380 New York St, Redlands, CA 92373
Points of interest (POI) by name and category. For example:
Disneyland
banks in Paris
los angeles starbucks
mount everest
Administrative place names, such as city/county/state/province/country namesSeattle, Washington
Postal codes92591 USA
You can use the following properties on the LocatorFindParameters class to refine or restrict search results when using
FindAsync:
Specify output fields to return in the geocoding response with the OutFields property.
Specify the spatial reference of result locations with the OutSpatialReference property.
Limit the number of candidates with the MaxLocations property.
Restrict searches to a specific country by setting the SourceCountry property.
Confine the search results to a specified area with the SearchExtent property.
Use the Location and Distance properties to prefer local candidates, which will then be ranked higher in the candidates list.
The following example searches for ice cream shops near a specified location and displays their name, phone number, and a link to
their website. The closest candidates are presented to the user at the top of the list.
// create a locator to search the ArcGIS Online World geocode service
var uri = new Uri("http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer");
var token = String.Empty;
var locator = new Esri.ArcGISRuntime.Tasks.Geocoding.OnlineLocatorTask(uri, token);
// get the locator's spatial reference
var info = await locator.GetInfoAsync();
var locatorSpatialRef = info.SpatialReference;
Related Topics
Features and graphics
Search for features
Search for coordinates
Initialize a LocatorTask
Whether you are performing online or offline geocoding, you start by initializing a LocatorTask object. Once you've initialized the
appropriate online or offline LocatorTask class, the programming pattern is exactly the same.
Online
To initialize an OnlineLocatorTask, declare an OnlineLocatorTask object, instantiate it with the new keyword, and pass the
uniform resource identifier (URI) to a REST endpoint that represents an ArcGIS Online Geocoding Service to the constructor. If the
service is secured, you also need to handle authenticating with the service using the appropriate mechanism. See the Security topic for
more information.
The following code sample shows how to create an OnlineLocatorTask for the World Street Map basemap layer using an ArcGIS
Online Geocoding Service:
// create a new online locator task for the World Street Map layer
var locator = new Esri.ArcGISRuntime.Tasks.Geocoding.OnlineLocatorTask(new Uri("http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer"));
Offline
To initialize an offline LocatorTask, declare a LocalLocatorTask object, instantiate it with the new keyword, and pass the path to
the locator (*.loc file) to the constructor.
The following code example shows how to create a LocalLocatorTask using a locally available locator (*.loc file):
// create a new local locator task using a locally available locator.
var locator = new Esri.ArcGISRuntime.Tasks.Geocoding.LocalLocatorTask("path to .loc file");
Input parameters
Use the LocatorTask to perform the reverse geocode on the geographic point by calling its ReverseGeocodeAsync method. At the
minimum, you need to provide the geographic location as a point in map coordinates, a search distance in meters from that location within
which a matching address should be searched, and a cancellation token with which to cancel the operation if required. An optional
parameter you can provide is the spatial reference in which the address candidate is to be returned.
Map location
To capture the input point geometry from a user, you can use a number of methods. For capturing the input point geometry for input
straight into the ReverseGeocodeAsync method, you can use the MapView.MapViewTapped event. The MapView control exposes
touch and mouse events such as the MapView.MapViewTapped event. You can add a MapViewTapped handler to the MapView
control.
The following code example shows how to capture the input point geometry using the MapView.MapViewTapped event to pass into
the ReverseGeocodeAsync method:
private async void mapView_MapViewTapped(object sender, Esri.ArcGISRuntime.Controls.MapViewInputEventArgs e)
{
graphicsLayer.Graphics.Add(new Graphic(e.Location));
OnlineLocatorTask locator = new OnlineLocatorTask(new Uri("http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer"));
var addressInfo = await locator.ReverseGeocodeAsync(e.Location, 50, SpatialReferences.Wgs84, CancellationToken.None);
}
Note: Because the call to ReverseGeocodeAsync is asynchronous, you must use the await keyword. This
means that the MapViewTapped event handler must also be marked with the async keyword, as shown in
the previous example.
For more complex operations where you want the input point geometry at a specific time in your code, you can use
mapView.Editor.RequestPointAsync. The MapView control has an associated Editor that is accessible from the Editor
property. In addition to helping you configure editing functionality, the Editor class provides methods for obtaining geometry from the
user. You can use the mapView.Editor.RequestPointAsync method on the Editor to get a point to reverse geocode from the
user. RequestPointAsync returns the user's map click as a MapPoint object. Because the call to RequestPointAsync is asynchronous,
you must use the await keyword. This means that the function that contains the call must also be marked with the async keyword.
The following code example shows how to capture the input point geometry and pass to the ReverseGeocodeAsync method using the
mapView.Editor.RequestPointAsync method:
var mapPoint = await mapView.Editor.RequestPointAsync();
var locator = new Esri.ArcGISRuntime.Tasks.Geocoding.OnlineLocatorTask(new Uri("http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer"));
var addressInfo = await locator.ReverseGeocodeAsync(mapPoint, 50, SpatialReferences.Wgs84, CancellationToken.None);
Search distance
You need to provide a search distance in meters from that location within which a matching address should be searched. If the search
distance is not provided or an invalid value is provided, a default value of 0 is used.
From this result object, you can obtain details for the found address from the LocatorReverseGocodeResult.AddressFields
property, and display the address to the user. You may want to show address information in a map overlay element. These elements are
commonly used to display custom labels for locations on the map, commonly referred to as MapTips. To learn more about map overlays,
see Display map overlays.
The following code example shows how to display the reverse geocoding address and address location in a basic map overlay element:
//Build the estimated reverse geocoding address string by reading values in the LocatorReverseGeocodeResultAddressFields property, which is a dictionary of strings
var address = addressInfo.AddressFields["Address"] + ", " +
addressInfo.AddressFields["City"] + ", " +
addressInfo.AddressFields["Region"] + " " +
addressInfo.AddressFields["Postal"];
//Create a textblock containing the address and add to the map overlay
var tb = new TextBlock();
tb.FontWeight = FontWeights.Bold;
SolidColorBrush myBrush = new SolidColorBrush(Windows.UI.Colors.Black);
tb.Foreground = myBrush;
tb.Text = address;
mapView.Overlays.Add(tb);
//To position the map overlay element at the address location, call MapView.SetMapOverlayAnchor and pass in textblock and a map point for the address location.
MapView.SetViewOverlayAnchor(tb, e.Location);
See the Add geocoding to your app tutorial to learn how to use the OnlineLocatorTask to perform geocoding and reverse geocoding
operations using an ArcGIS Online Geocoding Service.
Related Topics
Search for places
Search for features
Editing
Editing means that you can add, update, and delete features, online and offline. Updating features includes modifying feature
attributeschanging the value of a feature's fields according to the type and range of values allowedand modifying feature geometry,
such as moving a point feature or re-shaping a polygon feature.
Editing also includes adding, updating, and deleting feature attachments. For example, if you are editing features representing wildlife
sightings, the feature geometry can represent the sighting's location, the feature attributes can include the sighting's description and time,
and you can add a photo of the sighted wildlife as an attachment to the feature.
Whether your app enables users to edit online (connected), offline (disconnected), or both, editing always requires an associated feature
service. You can create fully-featured feature services using ArcGIS for Server, and basic hosted feature services using the ArcGIS for
Developers website. For more information, see Prepare an editing environment. You will ultimately submit any edits made to features in
your Runtime app to a feature service. In an online editing workflow, edits should be sent back to the associated service as soon as they
are made. For an offline editing workflow, before going offline, create a local geodatabase from a sync-enabled feature service to contain
the features you want to edit. Edits made to those features while offline are recorded in the geodatabase and can be synced with the
originating feature service when back online.
Workflows
You can use the ArcGIS Runtime SDK for .NET to build an app that lets users edit online, offline, or both. After creating a feature table
from a feature service or geodatabase, you can edit the features in the table using add, update, and delete methods. A feature layer
(FeatureLayer class) displays your features on the map, but the editing operations are performed on the underlying feature table
(GeodatabaseFeatureTable and ServiceFeatureTable classes).
Note: The code to implement feature table edits is the same regardless of whether the feature table is based on a
feature service (online source) or local geodatabase table (offline source). For offline editing workflows,
additional code is needed to Sync offline edits back to the feature service.
Online editing
If you are building an app for which you can assume network connectivity is always available, you can support editing with a
ServiceFeatureTable. This table contains features from an online data source (feature service) and can be displayed in a
FeatureLayer.
Similarly, if you are building an app that needs to support both online and offline editing workflows, you can support offline editing with a
GeodatabaseFeatureTable. This table contains features from a local data source (geodatabase) and can also be displayed in a
FeatureLayer. The data in a GeodatabaseFeatureTable, while stored locally, can be synchronized with an online feature service
when connectivity is available. Logic in your app can respond to connectivity changes and use online or offline data and editing
strategies as appropriate.
For more information on editing geodatabase feature tables online and offline, see Edit features.
Offline editing
If you are building an app in which your users need to edit features offline, use the editing workflow described in Edit features. Before
going offline, provision a local geodatabase using ArcGIS for Desktop or create one from a sync-enabled feature service using the API,
as described in Create an offline map. Edit the features in the geodatabase on your local machine when offline, and sync those edits
back to the service when online again, as described in Sync offline edits.
feature service to an ArcGIS server with the Feature Access capability enabled. This creates REST URLs, or endpoints, to a map service
and a feature service. Use these URLs to reference the services in your app. The map service endpoint can be used for read-only access
to features (viewing only), so make sure to reference the feature service endpoint in an editing app. For an offline editing workflow, create
a sync-enabled feature service. A sync-enabled feature service allows you to generate a geodatabase for offline use, and gives you the
ability to sync your local edits back to the service.
Note: ArcGIS Server 10.2.2 or greater is required to publish sync-enabled feature
services.
You can also create basic hosted feature services using the ArcGIS for Developers site, including sync-enabled services. Log in to the site
and access the Hosted Data section shown below, click New Feature Service, then follow the instructions.
Edits made to features in your Runtime application need to be committed back to the feature service. In an online editing workflow, edits
should be sent back to the service as soon as they are made. For an offline editing workflow, sync edits made to the features in a local
geodatabase back to the service, as described in Sync offline edits.
For some editing workflows, it's a good idea to have an analyst using ArcGIS for Desktop periodically review the edits to verify data
integrity. Although components in the API can perform some data validation, other tasks such as validating topologies cannot be
performed.
Related Topics
Edit features
Sync offline edits
Work with feature attachments
Features and graphics
Edit features
You can let users edit features while online (connected) or offline (disconnected). Editing includes adding new features, deleting features,
and updating existing features by changing their geometry (location or shape), attributes, or attachments. There are two models for editing
features: feature table editing and feature layer editing. This topic focuses on feature table editing. For an introduction to editing and the
editing models, see Editing.
Whether you are online or offline, the workflow to edit features is similar. In both cases, you need to do the following:
1. Create a feature tableIn a connected workflow, create it from a feature service. In a disconnected workflow, create it from a
geodatabase you generated with a sync-enabled feature service before you went offline, as described in Create an offline map.
2. Create a feature layer from the feature table and add the layer to the map.
3. Perform any edits against the feature table (add, update, and delete features and feature attachments).
4. Commit your editsIn a connected workflow, apply any edits you make to the feature service right away. In a disconnected
workflow, sync all your edits back to the service once you have a network connection, as described in Sync offline edits.
In a connected workflow, the type of feature table you create and edit is a ServiceFeatureTable. In a disconnected workflow, the type
of feature table you create and edit is a GeodatabaseFeatureTable. Both of these classes are types of ArcGISFeatureTable. The
class hierarchy between these is as follows:
To update or delete features, your app should enable users to select features on the map, as described below in Select features.
Online
In an online workflow, create a geodatabase feature service table (ServiceFeatureTable class) from a feature service. You can then
create a feature layer using this feature table. Once you add the feature layer to a map, features in the map extent are added to the
feature service table and can be edited. As you pan and zoom the map (that is, change the map extent), more features are retrieved
from the feature service and added to the geodatabase feature service table.
Note: The number of features you see when you initially visit a new area of the map is limited by the feature
service's MaxRecordCount property (the default value for this property is 1,000). Pan and zoom to query
the service for more features. Once features are retrieved from the service and visible in your map, they
are available in your geodatabase feature service table for editing and querying.
If you define a FeatureLayer using XAML, the underlying ServiceFeatureTable will be projected to align with the spatial
reference defined for the containing MapView. When initializing a ServiceFeatureTable instance in your code, however, you can
optionally pass in a spatial reference for the table. If you do not explicitly set the spatial reference when initializing the
ServiceFeatureTable, the spatial reference of the service will be used. Be aware that if your map is in a different spatial reference
than the default spatial reference of your ServiceFeatureTable, your features will not appear on the map. When possible, it's
therefore a good practice to set the spatial reference explicitly.
The following example illustrates creating feature layers using XAML. The ServiceFeatureTable used for each layer will be
automatically projected to the spatial reference of the map view (defined by the basemap layer).
<esri:MapView x:Name="MyMapView">
<esri:Map>
<layers:ArcGISTiledMapServiceLayer
ID="BaseMap"
ServiceUri="http://services.arcgisonline.com/arcgis/rest/services/World_Topo_map/mapserver"/>
<layers:FeatureLayer ID="MarineOnline">
<layers:FeatureLayer.FeatureTable>
<data:ServiceFeatureTable
ServiceUri="http://sampleserver6.arcgisonline.com/arcgis/rest/services/Sync/SaveTheBaySync/FeatureServer/0"/>
</layers:FeatureLayer.FeatureTable>
</layers:FeatureLayer>
<layers:FeatureLayer ID="BirdsOnline">
<layers:FeatureLayer.FeatureTable>
<data:ServiceFeatureTable
ServiceUri="http://sampleserver6.arcgisonline.com/arcgis/rest/services/Sync/SaveTheBaySync/FeatureServer/1"/>
</layers:FeatureLayer.FeatureTable>
</layers:FeatureLayer>
</esri:Map>
</esri:MapView>
The example below illustrates creating a feature layer using code. The spatial reference for the ServiceFeatureTable is set by
passing the spatial reference of the map view as the optional argument. This ensures that the features will display on the map as
expected.
// create a new geodatabase feature service table; point to a feature service layer end point
var table = new ServiceFeatureTable();
table.ServiceUri = "http://sampleserver6.arcgisonline.com/arcgis/rest/services/Sync/SaveTheBaySync/FeatureServer/1";
// initialize the feature table; use the map view's spatial reference for the optional "sr_override" argument
await table.InitializeAsync(MyMapView.SpatialReference);
// if the table was initialized successfully, create a new feature layer for the table and add it to the map
if (table.IsInitialized)
{
var lyr = new FeatureLayer
{
ID = "Birds",
DisplayName = "Bird Observations",
FeatureTable = table
};
MyMapView.Map.Layers.Add(lyr);
}
Note: The static method ServiceFeatureTable.OpenAsync can also be used to instantiate a new
ServiceFeatureTable with a specified spatial reference.
Offline
In an offline workflow, generate a geodatabase from a sync-enabled feature service while you have a network connection. Follow the
geodatabase generation process described in Create an offline map. This process results in a geodatabase stored locally on disk. The
geodatabase contains one or more feature tables, one for each service layer or service table that you requested in the geodatabase
generation process. When offline, create geodatabase feature tables (GeodatabaseFeatureTable class) from the geodatabase, for
example, on application load. The features in the geodatabase feature tables are available for editing whether you create a feature layer
or not, but in most cases you'll want to create a feature layer from the feature tables to display the features on a map. Also, consider
generating an offline basemap to give the feature data some geographical context when your users edit offline, as described in Include
a basemap.
The following code sample shows how to create a feature table from a table in a local geodatabase:
// open a geodatabase in local storage
var localData = Windows.Storage.ApplicationData.Current.LocalFolder;
var gdbPath = localData.Path + @"\WildlifeLocal.geodatabase";
var gdb = await Esri.ArcGISRuntime.Data.Geodatabase.OpenAsync(gdbPath);
// get the first table in the database
var table = gdb.FeatureTables.FirstOrDefault();
The following code sample shows how to create a feature layer from a feature table:
Add features
To insert a new feature into a geodatabase table, call the AddAsync method, which is overloaded to accept either a Feature object
(created using the appropriate geodatabase table schema), or the geometry and attributes you want to store. This method returns the
unique feature ID of the added feature, which you can use if you need to modify the feature later on. Adding a feature to a geodatabase
table is shown in the code below:
// get a point from the user
var mapPoint = await MyMapView.Editor.RequestPointAsync();
// open the local geodatabase
var gdb = await Esri.ArcGISRuntime.Data.Geodatabase.OpenAsync(geodatabasePath);
// open the "Marine" table and create a new feature using its schema
var gdbTable = gdb.FeatureTables.FirstOrDefault(t => t.Name == "Marine");
var newFeature = new Esri.ArcGISRuntime.Data.GeodatabaseFeature(gdbTable.Schema);
Update features
Features can be updated with the UpdateAsync method on the GeodatabaseFeatureTable.
The code sample below shows a method that updates a point feature in the geodatabase feature table with a new point geometry,
changing its location on the map.
// create a list of the record IDs to update (just one in this case)
var idList = new List<long> { this.lastAddedOid };
// query the table for the features with the specified IDs
var updateFeatures = await gdbTable.QueryAsync(idList);
Delete features
Features can be deleted from a local GeodatabaseFeatureTable by calling the DeleteAsync method. This method is overloaded to
allow you to specify the features you want to delete in several ways. To delete a single feature, you can pass in either the
GeodatabaseFeature itself or only its feature ID. To delete several features, you can specify a list (IEnumerable<long>) of IDs for
the features you want to delete. This is especially useful for deleting the current set of selected features in a FeatureLayer, which can
be returned using the SelectedFeatureIDs property. The following example illustrates calling DeleteAsync with a list of feature IDs.
var lyr = MyMapView.Map.Layers["MyFeatureLayer"] as Esri.ArcGISRuntime.Layers.FeatureLayer;
var selectedIds = lyr.SelectedFeatureIDs;
await gdbTable.DeleteAsync(selectedIds);
Select features
In a typical map application involving editing, users should be able to select features they want to edit. You can programmatically select
features in a feature layer by passing a set of feature IDs to the SelectFeatures method on FeatureLayer. You typically obtain
feature IDs by performing a query on the geodatabase table from which the feature layer was created, or by letting your users click the
map and obtain the IDs of any features within a certain pixel tolerance around the clicked point. The following code sample shows how to
use a touch event listener on the map to select clicked features:
private async void MyMapView_TouchUp(object sender, TouchEventArgs e)
{
// get the layer you want to select from (FeatureLayer)
var lyr = MyMapView.Map.Layers["MarineOffline"] as FeatureLayer;
if (lyr == null) { return; }
Online
In a fully connected workflow, you should apply feature edits and attachment edits back to the service as you make them. That way,
anyone else using the same feature service will have access to your changes right away.
To commit your feature edits to the service, call the ApplyEditsAsync method on ServiceFeatureTable. Pass in true to require
all edits to succeed in order to be committed, or false to commit edits individually. You can get the count of current feature edits using
AddedFeaturesCount, UpdatedFeaturesCount, and DeletedFeaturesCount. This indicates the number of features that will be
committed to the service upon calling ApplyEditsAsync.
The ApplyEditsAsync method returns a FeatureEditResult object. This object has properties for getting information about
individual feature edits that were attempted on the server as a result of the call: AddResults, UpdateResults, and DeleteResults.
Each of these properties returns a read-only list of FeatureEditResultItem that provides the object ID, global ID, success flag, and
error details (if an edit failed).
The following example shows applying edits to the server and then evaluating the result.
// store the count of edits that need to be applied to the server
var totalAdds = table.AddedFeaturesCount;
var totalUpdates = table.UpdatedFeaturesCount;
var totalDeletes = table.DeletedFeaturesCount;
// apply edits, get the edit result
var editResult = await table.ApplyEditsAsync(false);
// count successful feature edits
var added = 0;
var updated = 0;
var deleted = 0;
// loop through all add results, count success
foreach (var add in editResult.AddResults)
{
if (add.Success) { added++; }
}
// loop through all update results, count success
foreach (var update in editResult.UpdateResults)
{
if (update.Success) { updated++; }
}
// loop through all delete results, count success
foreach (var delete in editResult.DeleteResults)
{
if (delete.Success) { deleted++; }
}
// report edit status
var msg = new StringBuilder();
msg.AppendLine("Successfully added " + added.ToString() + " features of " + totalAdds.ToString() + " attempted.");
msg.AppendLine("Successfully updated " + updated.ToString() + " features of " + totalUpdates.ToString() + " attempted.");
msg.AppendLine("Successfully deleted " + deleted.ToString() + " features of " + totalDeletes.ToString() + " attempted.");
EditStatusTextBlock.Text = msg.ToString();
Note: For descriptions of errors that can arise during edit commits, go to the Apply Edits (Feature Service) topic
and click the error code link in the Description section.
Offline
In a disconnected workflow, commit all edits back to the service, and optionally pull the latest changes from the service back to your
geodatabase through a sync operation, as described in Sync offline edits. Syncing requires a network connection; therefore, do this
when you are back online. Note that the edits that are last committed to the service will overwrite previously committed edits, even if
committed edits were made at a later time.
Related Topics
Editing
Work with feature attachments
Sync offline edits
Features and graphics
Note: In a sync operation, edits most recently synced to the service will overwrite previously synced edits,
regardless of time of edits.
For descriptions of errors that can arise when syncing offline edits, see Error handling with sync.
Caution: Once you call unregister on a geodatabase, you cannot re-register the same
geodatabase.
If the original geodatabase is ever unregistered, no additional clients can use that copy
to register.
For a list of benefits of this workflow, see Register a geodatabase in a pre-planned workflow in "Create an offline map."
Code sample
The following sample shows how to sync your offline edits back to a feature service.
Related Topics
Editing
Edit features
Features and graphics
Work with feature attachments
Note: The following file extensions are supported for feature attachments: 7Z, AIF, AVI, BMP, DOC, DOCX, DOT,
ECW, EMF, EPA, GIF, GML, GTAR, GZ, IMG, J2K, JP2, JPC, JPE, JPEG, JPF, JPG, JSON, MDB, MID,
MOV, MP2, MP3, MP4, MPA, MPE, MPEG, MPG, MPV2, PDF, PNG, PPT, PPTX, PS, PSD, QT, RA, RAM,
RAW, RMI, SID, TAR, TGZ, TIF, TIFF, TXT, VRML, WAV, WMA, WMF, WPS, XLS, XLSX, XLT, XML, and
ZIP.
When creating a local geodatabase from a feature service, you can control whether or not attachments are included in the output data.
See the Create an offline map topic for more information and an example.
Query attachments
Attachments must be enabled for a service before you can store them for features. Before attempting to get attachments for a feature, first
check to see if the layer allows them. Even if attachments have been enabled for a feature service, it's possible that many features in the
dataset will not have associated attachments. Do not assume that all features in an attachment-enabled service will have attachments
defined.
To check whether a feature layer supports attachments, use the HasAttachments property defined on the associated
ArcGISFeatureTable. The following code checks whether attachments are supported for any of the feature layers in the map:
After verifying that a feature table supports them, information about attachments can be returned for a specified feature using the
QueryAttachmentsAsync method on ArcGISFeatureTable. The ID of the feature is passed into the method and an
AttachmentInfos object is returned.
Note: For an online feature layer, ServiceFeatureTable provides an overload that allows you to run the query
on the local cache of the table rather than on the service. This is more efficient if you're confident that the
cached data is still accurate, since it saves a round trip to the server.
The AttachmentInfos result provides a collection of AttachmentInfo objects with metadata about each attachment. If the feature
doesn't have attachments, the collection will be empty. The following example queries the table for attachments for a specified feature. A
check is then made to determine if the Infos collection is empty.
// query attachments for a feature
var attachmentResult = await featureTable.QueryAttachmentsAsync(featureId);
// check if any were found
if (attachmentResult.Infos != null && attachmentResult.Infos.Any())
{
foreach (var info in attachmentResult.Infos)
{
// ... process each attachment result ...
}
}
await bitmap.SetSourceAsync(stream.AsRandomAccessStream());
// create a new Image control to display the bitmap
var img = new Image();
img.Source = bitmap;
// show the file name in the tool tip
ToolTipService.SetToolTip(img, info.Name);
table are stored in-memory. To push attachment edits to the service, you must call ApplyAttachmentEditsAsync on the
ServiceFeatureTable.
A new attachment can be added for a feature if:
The service supports adding attachments (CanAddAttachment returns true).
The file size is under the maximum value set for upload to the service. By default, this value is 2 GB but can be changed by the
server administrator.
The file is one of the supported types (listed previously in this topic).
The following example adds a text file as a feature attachment. After adding the attachment, the edits are applied to the underlying
feature service. A check is made after both making and applying the edit, and an exception is thrown if an error is found.
try
{
// get data from a local file to add as an attachment
var openPicker = new FileOpenPicker();
openPicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
openPicker.FileTypeFilter.Add(".txt");
var attachmentFile = await openPicker.PickSingleFileAsync();
var fileStream = await attachmentFile.OpenStreamForReadAsync();
// check the edit results (specifically, the single Add result) for success
var serverAddResult = applyResult.AddResults.FirstOrDefault();
if (serverAddResult.Error != null)
{
// problem applying the attachment edit to the service
throw new Exception("Error applying attachment edit: " + serverAddResult.Error.Message);
}
}
catch (Exception exp)
{
// report the exception
Caution: Attachment edits may be successful in the in-memory feature table but fail when applied to the feature
service. An unsupported file extension, for example, does not fail when you add an attachment to the in-
memory table but does when edits are applied to the service. Since no exceptions are thrown, check the
attachment edit results, as shown in the previous example.
Delete attachments
One or more attachments can be deleted for a feature by calling DeleteAttachmentsAsync on ArcGISFeatureTable. Pass in the
ID of the feature and an array specifying the IDs of the attachments to delete. Before attempting to delete attachments, check the value
of CanDeleteAttachment to verify that the operation is supported. Finally, to apply all current attachment edits from the in-memory
feature table to the underlying feature service, call ApplyAttachmentEditsAsync on ServiceFeatureTable.
The following example illustrates using CanDeleteAttachment to determine if deleting attachments is allowed by the service. After
deleting attachments, it checks the AttachmentResult collection for errors to determine if the edits were successful. The in-memory
edits are then pushed to the service by calling ApplyAttachmentEditsAsync before checking for errors a final time.
// check for errors in applying the (three) attachment deletions to the service
var serviceEditErrors = from r in deletedAttachments.Results where r.Error != null select r;
if (serviceEditErrors.Any())
{
// ... report errors here ...
}
Update an attachment
Updating an attachment is essentially the same as deleting an existing attachment and re-adding it with new data or properties. A
common scenario for updating a feature attachment is to replace the information stored in the attachment with more up-to-date data. A
fast food restaurant feature, for example, may have a text file attachment that shows current specials. The data held by the attachment
could be updated as the information changes without changing the name, ID, or content type of the attachments.
To update an attachment, call UpdateAttachmentAsync on ArcGISFeatureTable and pass in the ID of the target feature, the ID
of the attachment to update, the data stream for the attached file, the file name to use for the attachment, and (optionally) the content
type.
A feature attachment can be updated if:
The service supports updating attachments (CanUpdateAttachment returns true).
The size of the new file is under the maximum value set for upload to the service. By default, this value is 2 GB but can be
changed by the server administrator.
The updated file is one of the supported types (listed previously in this topic).
The following example queries a feature for its attachments and loops through them to find one that needs to be updated (identifying it
by name). Once found, the ID of the attachment is used in a call to UpdateAttachmentAsync to replace the attachment data with the
contents of a new file. The name of the attachment is left as is.
// get attachments for a specific feature
var attachmentResult = await featureTable.QueryAttachmentsAsync(featureId);
// loop thru all attachments and find the one that needs updating (by name)
foreach (var info in attachmentResult.Infos)
{
if (info.Name == "WeeklySpecials.txt")
{
// read the updated information into a stream
// update this attachment with the new info (can keep the same name for the attachment)
var updateResult = await featureTable.UpdateAttachmentAsync(featureId, info.ID, fileStream, "WeeklySpecials.txt");
Related Topics
Edit features
Sync offline edits
Find a route
Routing is the process of finding paths through a transportation network. To calculate routes and obtain directions, the API provides a
specific RouteTask class. Using this task, you can optimize the results to find the shortest or the fastest route, reorder stops to find the
best sequence, avoid restricted areas and maneuvers, and specify time windows of arrival and departure for each stop.
The route task requires either a local ArcGIS Network Dataset on your machine to compute routes or access to a remote ArcGIS Network
Analyst Service. When using a local network dataset, routes can be computed locally even when there is no network connectivity. Using
remote services requires a network connection but is an opportunity for incorporating additional functionality such as real time traffic
updates.
Network datasets are designed to model transportation networks. They are created from source features, which can include simple
features representing roads, bridges, tunnels, bike paths, train tracks, and various other elements in the network. The geometry of the
source features helps establish connectivity between these elements. When you compute a route, the analysis happens on an indexed,
high-performance ArcGIS Network Dataset.
Network Analyst services are based on network datasets. They also contain analysis layers. These analysis layers correspond to specific
types of network analysis such as generating a route or calculating a service area. Analysis layers are exposed in the service as
operations. A RouteTask requires the service to contain a route analysis layer in order to compute routes.
Network Analyst services can be hosted in Esri's cloud platform, ArcGIS Online, or can be published on your own on-premises ArcGIS
servers. These services provide an ArcGIS REST API for clients such as mobile and web app. To find the URL for a Network Analyst
service, you can use the ArcGIS Services Directory.
Online
To initialize an online RouteTask, declare an OnlineRouteTask object, instantiate it with the new keyword, and pass the uniform
resource identifier (URI) to a REST endpoint that represents a route analysis layer in a Network Analyst service to the constructor. If the
service is secured, you also need to handle authenticating with the service using the appropriate mechanism.
The following code sample shows how to create an online route task for the route analysis layer in the secured Route_World service on
ArcGIS Online:
//create a new online route task for the route layer in the Route_World service
Esri.ArcGISRuntime.Tasks.NetworkAnalyst.OnlineRouteTask task = new Esri.ArcGISRuntime.Tasks.NetworkAnalyst.OnlineRouteTask
(new Uri("http://route.arcgis.com/arcgis/rest/services/World/Route/NAServer/Route_World"));
Note: You must have an ArcGIS Online organizational account in order to connect to the world route service
used in the previous example. Visit the Esri website for information about pricing and trial subscriptions.
Connecting to secured services is described in the Security topic.
Offline
To initialize an offline RouteTask, declare a LocalRouteTask object, instantiate it with the new keyword, and pass the path to the
.geodatabase file of your local network dataset and the name of the network to the constructor.
The following code sample shows how to create an offline RouteTask:
//create a new online route task for the route layer in the ESRI_Route_NA service
Esri.ArcGISRuntime.Tasks.NetworkAnalyst.LocalRouteTask task = new Esri.ArcGISRuntime.Tasks.NetworkAnalyst.LocalRouteTask
("path/to/routingGdb.geodatabase","Routing_Network");
However, you may want to calculate routes using the defaults specified in the service. In such cases, you first need to use
GetDefaultParametersAsync on the route task to get the default values. The default values are returned to the route task's delegate
as a RouteParameters object.
The following code sample shows how to use GetDefaultParametersAsync on the RouteTask to get the default values:
//use GetDefaultParametersAsync to get the default values.
Esri.ArcGISRuntime.Tasks.NetworkAnalyst.RouteParameters myRouteParameters = await task.GetDefaultParametersAsync();
The following sections describe some of the inputs you can provide to a RouteTask.
Stops
Use the SetStops method to specify locations that must be visited along the route. You need at least two stops to calculate a valid
route; however, you can add more if you like.
To specify stops for the route, you can specify a collection of MapPoints. The order indicates, by default, the sequence in which stops
will be visited on the route. However, if you enable the FindBestSequence property on RouteParameters, the service will attempt to
reorder stops to find the optimal route.
You can also enable the PreserveFirstStop and PreserveLastStop properties on RouteParameters if you don't want the
origin and destination stops to be reordered.
Barriers
Barriers represent ad-hoc restrictions that must be taken into consideration when calculating a route. A barrier can specify a set of roads
or a region that must be completely avoided by the route, for example, a bridge that may be closed due to construction work. Some
barriers may permit travel through them albeit at an added cost. For example, an accident on a freeway may temporarily slow down the
traffic. This can be represented by a barrier that allows travel along the freeway but increases the travel time required.
As with stops, you can specify barriers with a collection of features. You need to provide barrier geometry including the location and
shape of the barrier. The geometry can be a point, polyline, or polygon. You can define a feature and assign these barrier features to
the RouteParameters object using SetPointBarriers , SetPolylineBarriers. or SetPolygonBarriers depending on the
type of geometry that was assigned to the feature. You need to create separate features for point, polyline, and polygon barriers.
Driving directions
RouteTask can return turn-by-turn driving directions for the route if you enable ReturnDirections on RouteParameters. You can
specify the distance units to use through the DirectionsLengthUnits property. Depending on the languages supported by the
ArcGIS Network Analyst service, you can also specify which language to use through the DirectionsLanguage property. Depending
on the direction style supported by the ArcGIS Network Analyst Service, you can specify the DirectionsStyleName property. To
learn more about driving directions, see the Get driving directions tutorial and the topic Display driving directions
Impedance
The ImpedanceAttributeName property specifies a cost that should be minimized in the resulting route. For example, impedance
could be set to Time to calculate the fastest route or to Length to calculate the shortest route. Impedances supported by the service are
listed in the ArcGIS Services Directory under Network Dataset > Network Attributes with a Usage Type of esriNAUTCost.
U-turn policy
You can specify whether U-turns are allowed everywhere (AllowBacktrack), nowhere (NoBacktrack), only at dead ends
(DeadEndsOnly) , or only at intersections and dead ends (AtDeadEndsAndIntersections). Allowing U-turns implies the vehicle
can turn around at a junction and double back on the same street.
Result options
Line results
Using the OutputLines property, you can specify whether the geometry of the route feature should be simple straight lines
connecting all the stops or follow the true shape of the underlying transportation network. This is only applicable when using an
OnlineRouteTask and the RouteParameters.ReturnRoutes property is set to true. The following describes the available
options for route geometry output.
OutputLine.None: No route geometry is returned (travel time and distance are still reported)
OutputLine.Straight: Straight lines connecting the stops are returned
OutputLine.TrueShape: The shape of the route matches the underlying transportation network from which it was derived
OutputLine.TrueShapeWithMeasure: Same as TrueShape but includes route measurements that describe
accumulated travel cost across the routes
Note: The output line options are available to help limit response size for information you don't need when
working with online route tasks. Local route tasks will always return the full route result.
Geometry options
You can request that the geometry of the route feature be generalized by modifying the OutputGeometryPrecision and
OutputGeometryPrecisionUnit properties on RouteParameters. Generalizing geometry removes vertices that add more detail
beyond the precision you specify. Removing vertices makes the geometry smaller, saving time needed to transfer the geometry over
the network, and makes it faster to draw as a map graphic.
Enabling the IgnoreInvalidLocations property allows the RouteTask to return a route even if some stops are invalid, for
instance, if they are not reachable on the underlying transportation network. If this property is disabled, the RouteTask returns an
error even if one stop is invalid.
Restrictions
Restrictions allow you to place constraints on the analysis. For example, you can specify that the route should avoid toll roads. If the
route is for an emergency vehicle, you can specify that rules governing one-way streets should be relaxed. The restrictions supported by
the service are listed in the ArcGIS Services Directory under Network Dataset>Network Attributes with a Usage Type of
esriNAUTRestriction.
The following code sample applies restrictions to avoid passenger ferries and toll roads:
//create a list containing restrictions and assign these to the RestrictionsAttributeNames property
List<string> restrictions = new List<string>();
restrictions.Add("Avoid Ferries");
restrictions.Add("Avoid Toll Roads");
_routeParams.RestrictionAttributeNames = restrictions;
The following sections describe some of the inputs you can provide to a RouteTask.
Time windows
A time window specifies a period of time within which a stop should be visited on a route. For example, if you made appointments to
meet a number of customers at different locations, you can enable the UseTimeWindows property and specify a time window for each
location to get a route that will allow you to honor your appointments.
To enable time windows in your analysis, do the following:
Enable the UseTimeWindows property on RouteParameters.
Specify the time of departure from the origin using the StartTime property on RouteParameters.
Assign a time window to each stop. The time windows are specified on stops using the TimeWindowStart and
TimeWindowEnd attributes.
See the RouteParameters API Reference for a complete list of inputs for the RouteTask.
Calculate routes
Once you set up the input parameters, calculating routes is as simple as invoking SolveAsync on the RouteTask and passing in the
RouteParameters object to use in the calculation.
The operation's results are returned in a RouteResult instance, indicated by the Task<RouteResult> return type.
The following code sample handles the result:
try{
// Ensure you got at least one route back.
if (routeResult.Routes.Count > 0)
{
// Create a new graphic based on the first route and add to the route Graphicslayer
Esri.ArcGISRuntime.Layers.Graphic graphic = routeResult.Routes[0].RouteGraphic;
_routeGraphicsLayer.Graphics.Add(graphic);
}
}
catch (System.AggregateException ex)
{
// There was a problem, display the results to the user.
var innermostExceptions = ex.Flatten().InnerExceptions;
if (innermostExceptions != null && innermostExceptions.Count > 0)
{
string msg = innermostExceptions[0].Message;
Windows.UI.Popups.MessageDialog myMessageDialog = new Windows.UI.Popups.MessageDialog(msg);
myMessageDialog.ShowAsync();
}
else
{
string msg = ex.Message;
Windows.UI.Popups.MessageDialog myMessageDialog = new Windows.UI.Popups.MessageDialog(msg);
myMessageDialog.ShowAsync();
}
}
catch (System.Exception ex)
{
// There was a problem, display the results to the user.
string msg = "Error" + ex.Message;
Windows.UI.Popups.MessageDialog myMessageDialog = new Windows.UI.Popups.MessageDialog(msg);
myMessageDialog.ShowAsync();
}
The RouteResult object contains an array of Route objects representing the routes that were calculated. Each Route object contains
the following:
A graphic representing the route feature. The graphic's attributes provide information about route properties.
A list of graphics representing the stops that are visited by the route. Each graphic contains attributes that correspond to stop
properties. These properties provide valuable information about the stop as it pertains to the computed route.
A set of turn-by-turn driving directions (if you enabled ReturnDirections on RouteParameters).
The RouteResult object also contains an array of messages providing information about any warnings or errors encountered
while calculating the route.
Tasks throw exceptions if a problem is encountered as opposed to raising failed style events. Therefore it is important to make appropriate
use of the try/catch statement and handle these exceptions gracefully in your code.
The following image shows the map with route and directions displayed:
Related Topics
Display driving directions
Get directions
If you enabled ReturnDirections on RouteParameters, the returned RouteResult object contains a set of turn-by-turn driving
directions that you can add to your app. Each RouteDirection object contains textual directions information, duration, length, and
associated geometries for one step of a route.
The following code sample shows how to enable ReturnDirections on RouteParameters:
Esri.ArcGISRuntime.Tasks.NetworkAnalyst.RouteParameters routeParams = await _routeTask.GetDefaultParametersAsync();
routeParams.ReturnDirections = true;
The following sections describe some of the direction properties you can set on the RouteParameters class. Using the
RouteParameters class, you can specify the distance units to use through the DirectionsLengthUnits property, you can specify
which language to use through the DirectionsLanguage property, and you can specify the direction style using the
DirectionsStyleName property. Because an ArcGIS Network Analyst Service supports specific languages, linear units, and style, it's
worth checking the information about the service available in the ArcGIS Services Directory, which can be accessed using the service
URL. For more information about services, see Using the Services Directory.
Direction language
Depending on the languages supported by the ArcGIS Network Analyst Service, you can specify which language to use through the
DirectionsLanguage property.
The following code sample shows how to specify the language, English (United States), using the DirectionsLanguage property:
routeParams.DirectionsLanguage = CultureInfo.CreateSpecificCulture( "en-US" );
The following code sample shows how to specify kilometers as the DirectionsLengthUnits property:
routeParams.DirectionsLengthUnit = Esri.ArcGISRuntime.Geometry.LinearUnits.Kilometers;
Display directions
The RouteResult object contains a set of RouteDirection objects representing turn-by-turn driving directions that you can add to
your application. Each RouteDirection object contains textual directions information, duration, length, and associated geometries for
one step of a route. You can iterate over the RouteDirection collection, and build a string for each step of the directions' textual
information, duration and length. Once you have a formatted string for each step of the directions, you need to display this information in
your app, and .NET provides many ways to do this. The approach shown in the following code is to create a TextBlock containing the text
and add it to a StackPanel.
The following code sample shows how to iterate over the RouteDirection collection and format a string for each driving direction for
display in a text block. To keep the example simple, the formatting used is very basic. This code will append a step number, followed by a
TAB , followed by the directions text, and finally a new line. The step variable is then incremented.
//Define the following variables to store driving directions as well as information about the route
var directionsBuilder = new System.Text.StringBuilder();
var totalMiles = 0.0;
var totalMinutes = 0.0;
var step = 1;
//Create the following loop to iterate over each RouteDirection in the RouteDirections collection:
foreach (var d in route.RouteDirections)
{
//Append the current directions text to the directionsBuilder variable (StringBuilder):
directionsBuilder.AppendFormat("{0} \t {1}", step.ToString(), d.Text + "\n");
step++;
// Keep a running total of the segment length (miles) and time (minutes):
totalMiles += d.GetLength(LinearUnits.Miles);
totalMinutes += d.Time.TotalMinutes;
}
The following image shows the driving directions displayed in the text block:
Additional information
For additional information about working with driving directions, see the Get driving directions tutorial.
To learn more about using geocoding functionality with ArcGIS Runtime SDK for .NET, see the Add geocoding to your app tutorial.
Related Topics
Find a route
Geometry operations
Geometry operations let you create geometries (shapes with locations) that represent real-world objects and let you compare and relate
those shapes.
The term "geometry" in ArcGIS refers to the location and shape of a real-world object or a geometric construct such as an area of interest
or a buffer area around an object.
For example, you may want to measure the area of a polygon representing a lake or district. Perhaps you have multiple geometries, and
you want to know their relationship to one another. Geometry is the fundamental element for performing spatial analysis. With ArcGIS
Runtime SDKs, you can perform spatial analysis by relating geometries in a near-endless number of ways. Additional examples are as
follows:
At a clicked point on the map, display the land area's vegetation type.
Verify that all the building polygons in a layer lie completely within one of the parcel polygons in another layer.
Determine whether a proposed school site is within 300 meters of any liquor store.
Create geometry
Geometries come in different types. A point may represent a light pole, a polyline may represent a street centerline, or a polygon may
represent a parcel of land. In addition to single points, polylines, or polygons, there are multipart types as well.
The API includes a geometry class. This base class represents a geometry of any type. There are also classes derived from the geometry
class to be used when the geometry type is explicit.
Multipoint An ordered collection of zero or more point locations in one Locations of multiple bore holes at a drilling
(MultiPoint) geometry site
Line A single two-vertex line The shortest path from one point to another
Polyline (Polyline) One or more lines, each with two or more vertices A road centerline
Polygon (Polygon) An area, possibly multipart, whose parts may have interior holes A group of islands
Envelope (Envelope) A 4-sided polygon with sides aligned to the x and y axes An area of interest
A geometry object contains a single geometry. The geometry class also has methods to operate on geometry objects. You can create
geometries in some task results by using methods that return geometry objects, and by invoking a class constructor. Examples are as
follows:
A find task finds features in a service using a text search, returning the geometry in the results. The geometry is constructed for
you by the API using data returned by the find task.
You can use an operation such as buffer to create a new geometry from another geometry plus a buffer distance.
You can call a constructor to create points, polygons, and so on, providing the necessary information for that specific geometry
type.
You can create new geometries from existing geometries by performing operations such as these:
BufferBuffer a geometry at a specified distance, creating a buffer polygon.
DensifyCreate a densified copy of the input geometry by adding vertices between existing vertices.
Symmetric DifferenceCreate a geometry that is the topological symmetric difference of two geometries.
Simplify
Geometry engine
The GeometryEngine performs geometric operations, such as measuring distance, determining spatial relationships, and altering
geometries, all locally on the client. Each of the geometry engine methods are static, which means they can be called directly on the class
(without instantiating an object variable).
var bufferPolygon = Esri.ArcGISRuntime.Geometry.GeometryEngine.Buffer(inputPoints, 200);
Measuring distance
Often, you want to know the length or area of a geometry. You may want to know the length of a river or the area of a county. There are
a number of ways to measure length and area using the geometry engine. You can measure simple distances and areas using the
Length and Area methods.
double lineLength = Esri.ArcGISRuntime.Geometry.GeometryEngine.Length(myPolyline);
double polyArea = Esri.ArcGISRuntime.Geometry.GeometryEngine.Area(myPolygon);
However, if you're measuring large areas or distances that need to take into account the curvature of the earth, use the
GeodesicLength or GeodesicArea method.
Disjoint geometries can be compared as to their distance from one another as follows:
Distance The 2-D planar distance between two geometries at their closest points of approach.
NearestVertex The vertex on the boundary of a line or polygon that is nearest to the specified point.
NearestCoordinate The coordinate on the boundary of a line or polygon that is nearest to the specified point. This
coordinate need not be a vertex.
Spatial relationships
When you have multiple geometries on a map, you may want to know their relationship to each other. For example, you may want to
know if a polyline representing a creek crosses through a polygon representing your property. Given two geometry objects, the
geometry engine can tell you whether a given spatial relationship is true of those geometries. The spatial relationship is determined by
whether the boundaries or interiors of a geometry intersect. The meaning of boundary and interior are well defined for each basic
geometry type.
BoundaryFor lines, the line's endpoints, or the endpoints of each line in a multipart line. For polygons, the line that
circumscribes the interior area or areas (for multipart polygons) or circumscribe any interior holes.
InteriorPoints are entirely interior and have no boundary. For lines and polygons, the interior is any part of the geometry that is
not part of the boundary.
The basic relationships the geometry engine supports are as follows:
ContainsThe base geometry completely contains the comparison geometry.
CrossesThe geometries share some interior area, but not all interior area.
IntersectsNot disjoint.
OverlapsThe intersection of two points, lines, or polygons is also a point, line, or polygon, respectively.
EqualsTrue if two input geometries are the same. False if either are null, have different geometry types, or are geometrically
distinct.
For each spatial relationship, there is a method that returns a Boolean value indicating whether that relationship is true of the two
geometries. For spatial relationships that are true of one geometry but not the other, such as Within or Contains, the geometry engine
considers the order of the geometries entered.
// This returns true ...
bool contains = Esri.ArcGISRuntime.Geometry.GeometryEngine.Contains(europePolygon, belgiumPolygon);
// This returns false ...
bool contains = Esri.ArcGISRuntime.Geometry.GeometryEngine.Contains(belgiumPolygon, europePolygon);
What if the vertices of a line are farther apart? What if one vertex was near the center of Reykjavik, Iceland, and the other near the center
of Oslo, Norway? The following map uses the projected coordinate system WGS 84 Web Mercator (auxiliary sphere) to display a map of
such a line:
The line appears straight when drawn on the plane of the map surface, passing through the Faroe Islands. On the map surface, this line is
the closest path between the points. But in the real world, the Earth is round. The shortest distance between points on the surface of the
Earth follows a geodesic path. The geodesic path would appear straight to an observer on the ground. However, the line is curved with
respect to the projected coordinate system used in the map.
It is important to remember that in both maps used here, the lines are approximations. When a map is projected onto a 2-D map surface
from a 3-D Earth image, the 2-D map cannot perfectly represent all the features on the map. Some objects are distorted, including the
path and length of lines, the area of polygons, and the relative position of points. This behavior is normal. The reason there are many
coordinate systems is that they are designed to reduce different types of distortion in different areas of the Earth. Keep this in mind when
choosing a coordinate system and whether to use the geodetic version of some geometry methods.
Geometry contents
At its core, a geometry is a collection of one or more vertices (locations) that may be connected, one to the next, in a linear order. A
geometry does not store the lines that connect the vertices, such as those that represent the boundary of a polygon. Instead, it stores the
vertices in linear order along a polylines path or around a polygon. The lines between the vertices are implied by this ordering.
Coordinates are used to denote the location of the vertices. Coordinates can represent 2-D (x,y) or 3-D (x,y,z) locations. The meaning of
the x,y,z-coordinates is determined by a coordinate system. The vertices and coordinate system together allow your app to translate a
real-world object from its location on the Earth to its location on your map.
Coordinate systems, also known as map projections, provide a common basis for communication about a particular place or area on the
Earth's surface. When data sets have the same coordinate system, they can be integrated within a map that uses that coordinate system.
Geometries with a coordinate system different from the maps can be reprojected (translated) to the maps coordinate system for display.
In addition to integrating data sets within maps, coordinate systems allow you to perform various integrated analytical operations such as
overlaying data layers that come from different sources.
In the API, a spatial reference class represents a coordinate system. It contains a coordinate system and helper methods to access and
use it. The spatial reference class is associated with several other API classes that need a coordinate system to function. For example,
layers have an associated spatial reference. Some task parameters, such as those for the query task and the local routing task, are spatial
reference objects.
To use the contents of a geometry object, you must know the associated spatial reference. It's meaningless to compare two geometry
objects or determine their spatial relationship if they have different spatial references. To display a geometry in a map layer, the geometry
must have either the same spatial reference as the layer or be projected to the layer's spatial reference. To use two objects together, if
those objects each have a spatial reference, they should have the same spatial reference.
When working with geometry operations, it's important that you understand the basics of spatial references (the different types of
coordinate systems there are, when you have to know about spatial references, and so on) that are outlined in Spatial references.
Z-coordinates represent the vertical aspect of a vertex, such as elevation for a location. Z-coordinates may be associated with a vertical
coordinate system. Generally, they are not used when drawing the geometry on a 2-D map display.
In some cases, vertex coordinates include measure values, often called m-values. M-values are used in linear referencing to calculate
values between polyline vertices. M-values are not used when drawing a geometry. A geometry can contain m-values without containing
z-coordinates.
Geometry classes include methods to determine whether the object includes z-coordinates or m-values. Some task parameters, such as
those for the find task, allow you to choose whether z-coordinates or m-values should be returned in the result geometries.
Related Topics
Spatial references
Local Server geoprocessing tools support
Geoprocessing
Geoprocessing provides tools and a framework to perform analysis and manage geographic data. The modeling and analysis capabilities
geoprocessing provides make ArcGIS a complete geographic information system.
Geoprocessing provides a large suite of tools for performing GIS tasks that range from basic buffer and polygon overlays to complex
regression analysis and image classification. The kinds of tasks to automate can be mundane, such as maneuvering a large amount of
data from one format to another, or the tasks can be quite creative, using a sequence of operations to model and analyze complex spatial
relationships. Examples of this include:
Calculating optimum paths through a transportation network
Predicting the path of wildfire
Analyzing and finding patterns in crime locations
Predicting which areas are prone to landslides
Predicting flooding effects of a storm
Geoprocessing is based on a framework of data transformation. A typical geoprocessing tool performs an operation on an ArcGIS dataset
(such as a feature class, raster, or table) and produces a new dataset as the result of the tool. Each geoprocessing tool performs a small,
yet essential operation on geographic data.
Geoprocessing allows you to combine a sequence of tools in what is called a model. In a model, the output of one tool is fed into another,
which allows you to automate your workflows. Geoprocessing tools and models can be shared with others by packaging them into an
easily shared geoprocessing package, or by creating web services.
You can add to the suite of system tools installed with ArcGIS Desktop by creating tools using ModelBuilder or Python. Tools you create
are called custom tools and become an integral part of geoprocessing, just like system tools. You can open and run your tools from the
Search, Catalog, or ArcToolbox window, use them in ModelBuilder and the Python window, call them from another script, add them as
toolbar buttons, and share them as web services or as a geoprocessing package.
You can take a quick tour of geoprocessing and explore all geoprocessing topics in more detail in the ArcGIS Desktop Help system.
Note: Both ExecuteAsync and SubmitJobAsync are asynchronous .NET methods. ExecuteAsync kicks off
a GP task to run synchronously on the server.
Tasks from an ArcGIS Server geoprocessing service supports an Execute Task or Submit Job operation. If the execution mode of the
task's parent service is synchronous, Execute Task is supported. If the service is asynchronous, Submit Job is supported.
Once a service is running, it is not possible to change the execution type. The asynchronous SubmitJobAsync method is
recommended for long running tasks you might want to cancel or if you want access to processing messages. Although Execute Task is
often described as synchronous, many APIs have provided a synchronous execute method that blocks the calling application thread
and an asynchronous execute method that cannot be cancelled but will not block the calling thread.
Related Topics
Local Server geoprocessing tools support
Run a geoprocessing task
Geoprocessing task parameters
The ExecuteAsync method asynchronously executes a geoprocessing task that has been defined with a synchronous execution type
(on the server). Asynchronous geoprocessing tasks are executed by calling SubmitJobAsync, which is described in the Submit a job to
a geoprocessing task section of this topic.
Note: Parameter information (name and type, for example) can be found by consulting the service's
REST page.
Execution messagesThe Messages property of GPExecuteResult returns a read-only list of messages that were generated
as the server executed the task (GPMessage objects).
Continuing the Drive time polygons example above, the following code locates a GPFeatureRecordSetLayer in the returned list of
output GPParameter objects and adds the result features as graphics in the map:
if (result != null)
{
// loop thru all output parameters
foreach (var p in result.OutParameters)
{
// find the output drive time polygons by type (GPFeatureRecordSetLayer)
if (p.GetType() == typeof(GPFeatureRecordSetLayer))
{
// (could also find it by name, which is documented in the REST page for the service)
// if (p.Name == "Output_Drive_Time_Polygons") {
// cast to GPFeatureRecordSetLayer
var gpFeatureLayer = p as GPFeatureRecordSetLayer;
// get the polygon features
var features = gpFeatureLayer.FeatureSet.Features;
// add them to the graphics overlay
_resultsOverlay.Graphics.AddRange(features.Select((feature, index) => new Graphic(feature.Geometry,_bufferSymbols[index])));
break;
}
}
}
The following code creates a Geoprocessor task for extracting data from layers on the server. Because the underlying service has been
created to use asynchronous execution, it will be called using SubmitJobAsync.
var serviceURL =
"http://sampleserver4.arcgisonline.com/ArcGIS/rest/services/HomelandSecurity/Incident_Data_Extraction/GPServer";
var taskName = "Extract Data Task";
var geoprocessor = new Geoprocessor(serviceURL + "\" + taskName);
Submitted The server has accepted the job request, and input parameters have been validated.
Waiting The job is waiting to start (server is busy with other requests).
Succeeded The server has successfully completed the job, and the output results are available.
Failed The job has failed to execute because of invalid parameters or other geoprocessing tool failures.
TimedOut Job execution has exceeded the time out threshold defined for the service.
Cancelling The server is cancelling the execution of the job based on the client's request.
Cancelled The request to run the job was cancelled by the client, and the server terminated the job execution.
The following example submits a job to extract data for a specified area. It then polls the server every two seconds with the job ID to
check the status of the job.
// submit geoprocessing job
var result = await geoprocessor.SubmitJobAsync(parameter);
// keep checking the job as long as the status indicates it's still running
while (result.JobStatus != GPJobStatus.Cancelled && result.JobStatus != GPJobStatus.Deleted
&& result.JobStatus != GPJobStatus.Succeeded && result.JobStatus != GPJobStatus.TimedOut)
{
// pass the unique job id to the server to check the job
result = await geoprocessor.CheckJobStatusAsync(result.JobID);
// wait 2 seconds before checking again
await Task.Delay(2000);
}
// job is complete ...
The following example handles a successful completion by prompting the user to download and save the resulting data archive. For an
unsuccessful completion, server messages are displayed in a text block in the app.
// if the job succeeded, allow the user to download the data and save it locally
if (result.JobStatus == GPJobStatus.Succeeded)
{
StatusTextBlock.Text = "Finished processing. Retrieving results...";
// get the output parameter (representing the output data file stored on the server)
var outParam = await geoprocessor.GetResultDataAsync(result.JobID, "Output_Zip_File") as GPDataFile;
// if the output is valid, download the data
if (outParam != null && outParam.Uri != null)
{
var webClient = new WebClient();
var streamData = await webClient.OpenReadTaskAsync(outParam.Uri);
if (dialog.ShowDialog() == true)
{
// save output data to selected local file
using (Stream file = (Stream)dialog.OpenFile())
{
streamData.CopyTo(file);
file.Flush();
file.Close();
}
}
}
}else{ // job was not successful
var messageText = string.Empty;
// loop thru all messages that were generated during execution
foreach (var msg in result.Messages)
{
// concatenate the message descriptions
messageText += msg.Description + "\n";
}
// show the messages (last of which may be an error, time out, or cancellation)
txtStatus.Text = messageText;
}
You can also build a URL in the format http://<catalog-url>/<ServiceName>/MapServer/jobs/<jobid> as shown in the
following example:
// start with the geoprocessing service URL, replace "GPServer" with "MapServer"
var resultUrl = geoprocessor.ServiceUri.AbsoluteUri.Replace("GPServer", "MapServer");
// add "jobs" and the successful job ID to the URL
resultUrl = resultUrl + "/jobs/" + result.JobID;
// create a new ArcGISDynamicMapServiceLayer with the result URL and add it to the map
var dynLayer = new ArcGISDynamicMapServiceLayer(new Uri(resultUrl));
this.MyMap.Layers.Add(dynLayer);
If a job has failed, the server will not create result resources such as a result map service.
Related Topics
Geoprocessing
Local Server geoprocessing tools support
Geoprocessing task parameters
Data type
The data type of the parameter specifies the type of value that the client must provide for the parameter. The value of a parameter can be
as simple as a string, long, double, boolean or date. Or it can be a featureset (a collection of features with attributes similar to
featureclass), table, or a raster. For example, if the data type is a long you must provide a numeric value between 2,147,483,648 and
2,147,483,647. Any other decimal or string values will result in unexpected behavior of the tool. Similarly, if it is a raster data type, you
must provide appropriate raster data to successfully run the tool. The list below shows the data types of a task parameter and its expected
values.
GPDataFile Any file type such as .txt, .pdf, .csv, and { "url" : "http://myserver/myfile" }
so on.
GPRasterDataLayer Raster data that consists of a matrix of cells (or { "url" : "http://myserver/lake.tif",
pixels) organized into rows and columns (grid) "format" : "tif" }
where each cell contains a value representing
information.
GPRecordSet Tables that are represented in rows and columns. {
"fields":[{"name":"Id","type":"esriFieldTypeString","alias":"Id"},
{"name":"State_Name","type":"esriFieldTypeString","alias":"State
Name"},
{"name":"State_Abbr","type":"esriFieldTypeString","alias":"State
Abbr"}],
"features" : [
{ "attributes" : {"Id" : 43, "State_Name" :
"California","State_Abbr":"CA"},
{ "attributes" : {"Id" : 67, "State_Name" :
"Colorado","State_Abbr":"CO"}]}
TypeString","alias":"Id"},
Related Topics
Geoprocessing
Local Server geoprocessing tools support
Run a geoprocessing task
ArcGIS Online
ArcGIS Online is a cloud-based, collaborative content management system for maps, apps, data, and other geographic content. You can
access ArcGIS Online through mobile devices, a website (www.ArcGIS.com), and desktop map viewers. With ArcGIS Online you can do
the following:
Create web maps.
Web enable your data.
Share your maps, data, and applications.
Find relevant and useful basemaps, data, and configurable GIS resources.
Manage content and users in your organization.
Tip: With your free ArcGIS for Developers account, you have access to ArcGIS Online for development and
testing. Sign in at developers.arcgis.com or www.ArcGIS.com.
Using ArcGIS Runtime, you can access and edit existing content and create new content items, comment and add ratings, search for
users and groups, and share and unshare items.
Learn more about developing with ArcGIS Online in ArcGIS Online Help.
Tip: Your free ArcGIS for Developers account includes some subscription-only services for development and
testing. Sign in at developers.arcgis.com or www.ArcGIS.com. If you upgrade your free account to a paid
plan, you can still sign in using both of these sites.
Learn more about ArcGIS for organizations on esri.com.
// call the static method CreateAsync without arguments to get a reference to the arcgis.com portal
ArcGISPortal portal = await ArcGISPortal.CreateAsync();
// get portal info and display it to the user
ArcGISPortalInfo portalInfo = portal.ArcGISPortalInfo;
From here, you can access public content; for example, you can display a web map, or download the data stored in a portal item. You
can also Search portal content such as web maps, map services, map features, groups, and users.
Some organizations share content publicly and allow anonymous access to that content; connect to publicly accessible content from
such organizations by specifying the organization URL, for example:
// call the static method CreateAsync with a Uri argument to get a reference to a specific portal
ArcGISPortal portal = await ArcGISPortal.CreateAsync(new Uri("http://anorganization.maps.arcgis.com"));
The portal object now has access to all the secure content for which the user has access rights and can find out more information about
the user, such as the full name (instead of the account user name). Additionally, information about the organization such as the name,
banner image, description, and so on, can be found as shown above. Apps often make use of this information when a user connects to
a specific portal, to show the user organization branding and context.
Typically, the portal object with the authenticated user is cached and used throughout the app session, to provide the app with a view of
a portal that is centered around a single user. When the app is restarted, the credentials must be reinstated, or the user must repeat the
authentication process.
To access secure content, an app needs to provide a way to sign in to the platform, a process often known as authentication. The
recommended approach for authenticating a user known to the platform is to use a user login and OAuth. Apps that target users who
are unknown to the ArcGIS platform can authenticate with the platform on behalf of the user by using an app login.
The portal class contains methods to authenticate using OAuth 2.0 for both user and app logins. Again, the authenticated portal object
can be cached and reused throughout the app session.
ArcGIS for Server services are listed below, along with the classes that make use of them.
Related Topics
Tutorial: Access maps and content from your portal
Access portal content
Search portal content
Security
The expression used to set the QueryString property can further refine search criteria using specific fields as well. In your query
expression, use a property identifier (such as orgid, owner, title, or type), followed by a colon and the value. The following
expression, for example, will search for web map items within the portal organization with id 123ABC that match the term Cache.
var searchParams = new Esri.ArcGISRuntime.Portal.SearchParameters("\"Cache\" orgid:\"123ABC\" type:(\"web map\" NOT \"web mapping application\")");
See the ArcGIS Rest API search reference for more information, including the fields available for use in your query expression.
The following example searches ArcGIS Online for web map portal items. The results are limited to a maximum of 20 items and will be
sorted in descending order (highest to lowest) on the number of views.
// create the search expression (searchTerm is passed in)
var queryString = string.Format("\"{0}\" type:(\"web map\" NOT \"web mapping application\")", searchTerm);
ArcGISPortal search methods, such as SearchItemsAsync, SearchGroupsAsync, and SearchUsersAsync allow you to provide
an optional CancellationToken argument that gives the user the ability to cancel execution of the search task. See the Asynchronous
programming topic for more information about allowing task cancellation.
Note: The fields available in a query expression for users or groups differ from those used for a portal items
search. See the ArcGIS Rest API search reference for more information.
More information
The following resources provide more information about working with portal content.
Tutorial - Work with portal content
Sample code -ArcGIS Runtime SDK for .NET samples
Complete app (source code) - ArcGIS Portal Viewer app
Related Topics
Tutorial: Access maps and content from your portal
Access the ArcGIS platform
Apps use portal items in different ways. They may show a user a range of items from a portal by combining the title, thumbnail image, and
other metadata. This approach is often used to allow users to browse web maps, basemaps, or map services, and identify the item to work
with. If a user selects an item, the app may then download the data stored in the portal item, for example, by opening and displaying a
web map in a map, or downloading a tile package. Apps sometimes access items directly by ID if a specific item should always be used.
Your app can also add new portal items and alter existing items by adding comments and ratings, updating item information, sharing,
unsharing, and deleting them, as long as the authenticated user has access permissions to do so.
You access the content of a portal item differently depending on its type. Below you can find examples of accessing different types of
portal items. For more information on connecting to a portal, see Access the ArcGIS platform. To find out how you can allow apps to
browse or search for items and groups, see Search portal content.
// get the map from the view model; display it in the app's map view
this.MyMapView.Map = webMapVM.Map;
// get a portal item using its ID (ArcGISWebException is thrown if the item is not found)
var item = await Esri.ArcGISRuntime.Portal.ArcGISPortalItem.CreateAsync(portal, "16055a012a4c4bfdb972c90e20b5e7b8");
// check type: if the item is not a web map, return
if (item.Type != Esri.ArcGISRuntime.Portal.ItemType.WebMap) { return; }
// get the map from the view model; display it in the app's map view
this.MyMapView.Map = webMapVM.Map;
// zoom to the extent of the bookmark
this.MyMapView.SetViewAsync(bookMark.Extent);
Note: Remember that the credentials must be for a valid user with access to
the item.
Note: The thumbnail of a portal item, along with the ratings and data, is not returned from the portal when you
initially create the item, in order to reduce the network traffic and memory requirements. See the section
below on how to access these properties.
Fetch thumbnails of items
When you create a portal item object, not all information associated with it is immediately returned. This allows you to work with the item
using a minimum amount of memory and delay fetching the larger pieces of data unless, or until, you really need them. Information you
need to fetch, if required, includes thumbnail images, ratings and comments, item data, group memberships, and user folder contents.
The following example shows how to create a bitmap image to display a portal item thumbnail.
The same applies to the thumbnails of other classes, like users, groups, and organizations. ArcGISPortalUser, ArcGISPortalGroup,
and ArcGISPortalItem all provide a ThumbnailUri property.
try
{
// create credential from input username and password
// (exception will be thrown here if login fails)
var creds = await IdentityManager.Current.GenerateCredentialAsync(
"https://www.arcgis.com/sharing/rest",
this.UsernameTextBox.Text,
this.PasswordTextBox.Password);
// add credential to the IdentityManager
IdentityManager.Current.AddCredential(creds);
// get the portal, the connection will be made using the credentials supplied above
var portal = await Esri.ArcGISRuntime.Portal.ArcGISPortal.CreateAsync(
new Uri("https://www.arcgis.com/sharing/rest"));
Note: As seen in the code above, user content is another example of information that you must explicitly fetch, like
portal item thumbnails and content.
To get items shared with the current user, or items owned by a different user, you need to search portal content.
Samples
You'll find a complete portal viewer app that illustrates working with portal content in the arcgis-portalviewer-dotnet github repository.
Related Topics
Tutorial: Access maps and content from your portal
Access the ArcGIS platform
Search portal content
Security
Security
Services provided by portal or by ArcGIS for Server may require a login before they can be accessed. Some portals may provide
anonymous access to some resources, but restrict access to others based on organization or group membership. You can add logic to
your app that allows the user to access secured content using one of several authentication methods.
Your app can provide access to secured ArcGIS Server, ArcGIS Online, or ArcGIS for Portal resources using the following authorization
methods:
Tokens: ArcGIS Tokens or OAuth
Network credential: HTTP secured service
Certificate: Public Key Infrastructure
See the Use ArcGIS token authenticationand Use OAuth 2.0 authentication topics for specific information about accessing resources
secured using those methods.
Once authenticated, you can get details about the user from the ArcGISPortal.CurrentUser property. This property returns an
ArcGISPortalUser object with properties that describe the user and methods for accessing the user's content. Depending on the value
of the Access level, personal details and content may be publically available, or only to the user and administrators.
Tip: Authenticating with ArcGIS for Portal or an organization account for ArcGIS Online also provides a way to
license your ArcGIS Runtime SDK app at the Standard level. See the License your app topic for more
details.
Identity manager
To abstract some of the low level details for working with secure content, the IdentityManager class handles some of the details when
accessing secured resources in your app, such as challenging the user for credentials when a secured resource is accessed and storing
credentials when the user successfully authorizes. It also manages a collection of server information and available user credentials if they
have been provided. When a request for secured content is made to one of the servers in the collection, the identity manager
automatically includes the user's credentials in the request or handles getting a credential if one does not exist.
IdentityManager.Current.RegisterServer(serverInfo);
The following members are available on the identity manager to work with registered servers:
ServerInfos - the collection of registered servers that provide secure content, represented as ServerInfo objects.
RegisterServer - a method that adds a new ServerInfo to the identity manger's ServerInfos collection.
FindServerInfo - locates and returns a ServerInfo, if it exists, from the registered server collection using the server URL.
Otherwise, the identity manager will challenge the user for login information according to the authorization method that's been defined
for the registered server. The following code will cause a challenge for the user to provide a login if the server is secured and registered
with the identity manager.
var portal = await ArcGISPortal.CreateAsync(new Uri(SERVER_URI));
Caution: If a server allows public access for unsecured resources, the user may be given access as an anonymous
user rather than being challenged for authorization. To explicitly challenge the user, call
IdentityManager.GetCredentialAsync().
The details of how a user is challenged for a credential (user name and password, in other words) are handled by components
associated with the IdentityManager.
Challenge handler - a component that implements the IChallengeHandler interface and is assigned to the
IdentityManager.ChallengeHandler property. The challenge handler contains logic for obtaining the required credential
for a server, either by providing hard-coded login information or prompting the user to enter it.
OAuth authorize handler - a component that implements the IOAuthAuthorizeHandler interface and is assigned to the
IdentityManager.OAuthAuthorizeHandler property. The OAuth authorize handler contains logic that's specific to
handling authorization using OAuth.
You can use the default handlers and utility classes provided by ArcGIS Runtime SDK for .NET. If needed, you can create custom
handler components by implementing the required interfaces. See the Use ArcGIS token authentication topic for more details about
setting up a challenge handler.
Related Topics
Access the ArcGIS platform
Use ArcGIS token authentication
Use OAuth 2.0 authentication
Note: Accessing secured services has major differences between the three APIs that make up ArcGIS Runtime
SDK for .NET (Desktop, Store, and Phone). Consult the documentation for each platform for which you need
to work with secured content.
Prompt the user for login information
If an attempt is made to access secured content in your ArcGIS Runtime SDK for .NET Windows Store app, a login dialog automatically
displays so the user can provide a user name and password. The login UI indicates the URL of the resource for which a login is required.
The user is warned if incorrect login information is entered, and can continue trying to log in. If the login UI is dismissed, the map displays
without the secured resource.
Note: The user can check the Remember my credentials check box to store credentials for this portal in the
app's local storage for use between sessions of your app.
To verify what's happening in your app when access to a secured resource is attempted, review the HTTP traffic using a tool like Fiddler.
Here's a summary of what you'll see:
1. A request is made to a secured resource. The server responds with an unauthorized access error.
2. Information about the portal that hosts the resource is requested. The response contains a tokenServicesUrl for obtaining
ArcGIS tokens with an authorized user name and password.
3. A user name and password are sent to the tokenServicesUrl. If the login is successful, the response contains a token (a long
alphanumeric string).
4. The request to the secured service is resent, this time with the token included in the URL query string. A successful response
returns.
5. All subsequent requests to the service (or any others hosted on the same portal) include the token.
In the following example, the IdentityManager is used to generate a credential for the specified portal. A user name and password are
hard-coded into the call to GenerateCredentialAsync. The credential is then stored with the IdentityManager before a secured
resource hosted by the portal is accessed.
try
{
var opts = new GenerateTokenOptions();
opts.TokenAuthenticationType = TokenAuthenticationType.ArcGISToken;
// generate an ArcGIS token credential with a hard-coded user name and password
// (if authentication fails, an ArcGISWebException will be thrown)
var cred = await IdentityManager.Current.GenerateCredentialAsync(
"http://serverapps10.esri.com/arcgis/rest/services/",
"user1",
"pass.word1",
opts);
// add the credential to the IdentityManager (will be included in all requests to this portal)
IdentityManager.Current.AddCredential(cred);
// load a layer based on a secured resource on the portal
var layer = new ArcGISDynamicMapServiceLayer(new Uri
("http://serverapps10.esri.com/arcgis/rest/services/GulfLawrenceSecureUser1/MapServer"));
await layer.InitializeAsync();
// add the layer to the map and zoom to its extent
this.MyMapView.Map.Layers.Add(layer);
await this.MyMapView.SetViewAsync(layer.FullExtent);
}
catch (ArcGISWebException webExp)
{
var msgBox = new MessageDialog("Unable to authenticate with portal: " + webExp.Message);
msgBox.ShowAsync();
}
catch (Exception exp)
{
var msgBox = new MessageDialog("Unable to load secured layer: " + exp.Message);
msgBox.ShowAsync();
}
In the previous example, accessing the secured content is transparent to the user. A credential is generated and stored with the identity
manager before an attempt is made to access data on the portal. With the request to the secured resource, the identity manager
automatically includes the required credential (ArcGIS token). From the user's perspective, the layer loads like any unsecured layer would.
Additionally, any other secured resources on the same portal to which the provided login has permission can also be accessed without
having to authenticate again.
Note: Assigning a challenge handler removes the default one used by the identity manager. To disable challenges
for secured content, for example, set IdentityManager.ChallengeHandler to null.
A challenge handler class must implement the IChallengeHandler interface, which defines a single method,
CreateCredentialAsync. The signature for this method is shown in the following example.
public async Task<Credential> CreateCredentialAsync(CredentialRequestInfo requestInfo)
As you can see, the challenge handler is responsible for returning a Credential. The CredentialRequestInfo that is passed into
CreateCredentialAsync can be used to discover the URI of the service.
The following example shows an implementation of CreateCredentialAsync that returns a credential for one of several portals using
hard-coded login information.
return cred;
}
To put this code into action, it must be a method of a class that implements IChallengeHandler, which must be assigned to the
IdentityManager.ChallengeHandler property. The following example creates a new challenge handler and sets the
ChallengeHandler property.
var myChallenger = new MyChallengeHandler(); // custom class that implements IChallengeHander
IdentityManager.Current.ChallengeHandler = myChallenger;
As a shortcut, you can create a new challenge handler using the Esri.ArcGISRuntime.Security.ChallengeHandler utility class
and passing in a function with the proper signature for the IChallengeHandler.CreateCredentialAsync method. The following
example shows creating a new challenge handler using this utility class.
var myChallenger = new Esri.ArcGISRuntime.Security.ChallengeHandler
(this.CreateHardCodedCredentialAsync);
IdentityManager.Current.ChallengeHandler = myChallenger;
Once the ChallengeHandler property is assigned, attempts to access secured resources will be funnelled through your challenge
handler (specifically, through the IChallengeHandler.CreateCredentialAsync method).
Caution: Specifying your challenge handler disables the default behavior that prompts for a user name and password
for secured services. If using the challenge handler illustrated above, for example, you would not be
prompted for a user name and password for secured resources hosted on a portal other than the three for
which credentials are provided.
Tip: Authenticating with ArcGIS for Portal or an organization account for ArcGIS Online provides a way to license
your ArcGIS Runtime SDK app at the Standard level. See the License your app topic for more details.
Note: Much of the work involved in these steps can be handled by ArcGIS Runtime. You will not need to write
code to implement the entire workflow.
Note: IdentityManager is a singleton class, which means there is always exactly one instance. You cannot
instantiate an IdentityManager object in your code using new, instead you must reference it using the
IdentityManager.Current static property.
IdentityManager maintains a collection of servers for your app that require authentication for access to secured services. You can
register a server with the identity manager with its URL and indicate what type of authorization should be used. For OAuth user or app
logins, you need to provide additional information about the client app:
Client IDAn alphanumeric string that identifies the app on the server. See the Get a Client ID and Secret section in this topic
for instructions on creating a client ID for your app with ArcGIS Online.
Redirect URIAn address to which a successful authentication response is sent. For a server app, this might be the URL of a
web service that can accept the authorization response. You can use the special value of urn:ietf:wg:oauth:2.0:oob to
deliver the response to a portal URL (/oauth2/approval). This value is typically used by applications that don't have a web server
or a custom URI scheme where the code can be delivered. When received by your app, the response is read from the
authentication success page.
The following example registers a server with the IdentityManager with an OAuth user login authentication type
(TokenAuthenticationType.OAuthAuthorizationCode) and defines some required information about the client app
(OAuthClientInfo).
// Register the portal to use OAuth authentication
var serverInfo = new ServerInfo
{
ServerUri = "https://www.arcgis.com/sharing/rest",
TokenAuthenticationType = TokenAuthenticationType.OAuthAuthorizationCode,
OAuthClientInfo = new OAuthClientInfo { ClientId = "2HEtx9ujil5rac8K", RedirectUri = "urn:ietf:wg:oauth:2.0:oob"}
};
IdentityManager.Current.RegisterServer(serverInfo);
When a request is made for a secured resource, the identity manager can see if the request is to one of its registered servers. If the
user has already authorized with the server, the identity manager automatically includes the user credential with the request. Otherwise,
the identity manager challenges the user for login information according to the authorization method that's been defined for the
registered server. The following code causes a challenge for the user to provide a login if the server is secured and registered with the
identity manager.
var portal = await ArcGISPortal.CreateAsync(new Uri(SERVER_URI));
Caution: If a server allows public access for unsecured resources, the user may be given access as an anonymous
user rather than being challenged for authorization. To explicitly challenge the user, call
IdentityManager.GetCredentialAsync().
The identity manager challenges requests for a secured resource on a registered server by redirecting the user to the login UI on the
server. If the user authorizes successfully, an access token is returned and stored with the identity manager.
An access token is an alphanumeric string that provides a key for accessing the platform on behalf of the user, and must be sent with all
requests for secured content on the server. The IdentityManager class manages access tokens for portals used by the app and
automatically includes one when needed for requests made by ArcGIS Runtime classes.
Note: When a user authenticates with a portal, in addition to the access token, the identity manager receives and
stores a refresh token. The refresh token is used to obtain a new access token when it expires. The
identity manager automatically handles getting the new access token using the refresh token when
needed.
To explicitly challenge the user to sign in, call IdentityManager.GetCredentialAsync as shown in the following example.
private async Task SignIn()
{
try
{
var crd = await IdentityManager.Current.GetCredentialAsync
(new CredentialRequestInfo { ServiceUri = PORTAL_URL }, true);
IdentityManager.Current.AddCredential(crd);
// access the portal as the authenticated user
this.portal = await ArcGISPortal.CreateAsync(new Uri(PORTAL_URL));
}
catch { } // can happen if user cancels the authentication
}
To sign out of a portal, you need to remove the credential stored with the identity manager. If the AllowSaveCredentials option is
enabled for the challenge handler, you also need to clear credentails that may have been saved. The following example removes the
credential for a particular server then reaccesses it with anonymous access.
private async Task SignOut()
{
// clear the credential for the server from the IdenityManager (if it exists)
foreach (var cred in IdentityManager.Current.Credentials)
{
if (cred.ServiceUri.Contains(PORTAL_URL)) {
IdentityManager.Current.RemoveCredential(cred);
}
}
// clear the credentials cache from the DefaultChallengeHandler so they won't be reused in the next session
var challenger = IdentityManager.Current.ChallengeHandler
as Esri.ArcGISRuntime.Security.DefaultChallengeHandler;
challenger.ClearCredentialsCache();
// access the portal as anonymous
this.portal = await ArcGISPortal.CreateAsync(new Uri(PORTAL_URL));
}
App logins
If your app targets users unknown to the ArcGIS platform, the app can log in to the ArcGIS platform and access secured resources to
which it has permission. Unlike the user logins described previously in this topic, your user will not be prompted with a UI to enter a login
and password. Instead, your app is required to authenticate with the portal to receive an access token.
What does an app use to authenticate? The equivalent of user name and password for an app is Client ID and Client Secret. For an
OAuth app login, your app needs to provide this information to the portal hosting the secured resources. As with a user login, your app
receives an access token that the identity manager can use for working with secured resources.
The Client ID is required for user logins, as described previously, as well as for app logins. Unlike user logins, however, an app login
also requires that you provide the Client Secret.
Caution: With an app's Client ID and Client Secret, a user can access secured and billable content on ArcGIS.com.
It's therefore important that you keep your app's Client Secret a secret. Care must be taken to prevent
malicious users from extracting the client secret from the application using developer tools. For most apps,
this implies that the app must have a server side component that keeps these credentials secure and
performs work on behalf of the app.
Although it's possible to run code on the client that gets an app login using the Client ID and Client Secret, it's not recommended to do
so if security is a concern. Remember that access to secured services by a malicious user may be billed to your app. This scenario is
described in more detail in the topic App logins and OAuth 2.0 with some suggestions as to how to secure the Client Secret.
Related Topics
Security
Use ArcGIS token authentication
Feature collection - Creates a GraphicsLayer and displays all features in the collection as graphics
OpenStreetMap basemapCreates an OpenStreetMapLayer
Layer from KML via URLCreates a KMLLayer
Note: The URL of the KML or KMZ (compressed KML) file must be publicly accessible for the layer to
display in your MapView. If you added a file to your ArcGIS Online account, the file/resource must be
public.
Note: You cannot edit layers created within ArcGIS Online as map notes. The ArcGIS Runtime .NET API treats
map note layers as feature collections and therefore presents them as graphics. You cannot apply graphic
edits back to the service, therefore editing is disabled.
Setting a minimum and maximum scale on layers
When you create or edit a web map on ArcGIS Online, you can set a minimum and maximum scale on any layer. This is done by clicking
the layer in the table of contents and, from the resulting list of options, choosing Set Visibility Range. If you've set a minimum scale on a
layer in a web map, the layer will no longer display in your MapView when you are zoomed out past this scale. If you've set a maximum
scale on a layer, the layer will no longer display if you are zoomed in beyond this scale.
Related Topics
Tutorial: Access maps and content from your portal
Work with web maps
To deploy an app, you must license it at either the Basic or Standard level. When deploying Runtime technology, costs are incurred only at
the Standard level. Usage of ArcGIS Online services may also incur costs. For details, see Terms of Use - FAQ and Plans. For an
overview of the current ArcGIS Runtime licensing model, see Licensing your Runtime app.
License your app for deployment by adding a few lines of code, as described in the following sections. After this is done, the watermark
and debug messages will no longer display and your app is ready to be deployed.
The following table shows which functionality will work for each license level:
3. Once you're logged in, the Applications section displays. If you havent already done so, register your app by clicking the
Register New Application button. On the page that displays, complete the fields, then click Register New Application.
In the page that displays, a client ID appears for your app.
4. Copy the client ID.
5. Use the following code to set the client ID in your app in a location in your project that comes before any ArcGIS Runtime
functionality is used:
Esri.ArcGISRuntime.ArcGISRuntimeEnvironment.ClientId = "mYcLieNTid";
After setting the ClientId property, initialize the runtime by calling the static Initialize method on the
ArcGISRuntimeEnvironment class. Make sure to wrap the call in a try/catch block as shown below. If the initialization
fails because of an invalid client ID, an exception will be thrown.
Esri.ArcGISRuntime.ArcGISRuntimeEnvironment.ClientId = "mYcLieNTid";
try
{
Esri.ArcGISRuntime.ArcGISRuntimeEnvironment.Initialize();
}
catch (Exception ex)
{
Console.WriteLine("Unable to initialize the ArcGIS Runtime with the client ID provided: " + ex.Message);
}
Steps:
1. Obtain and set the client ID for your app by following all of the Basic level licensing steps.
2. Allow the app user to authenticate with ArcGIS Online or Portal for ArcGIS. You must do this before any Standard level
ArcGIS Runtime functionality is used. As part of the process, save the license information in preparation for your app being
used in an offline environment for up to 30 days. This is achieved as follows:
// connect to ArcGIS Online or an ArcGIS portal as a named user
// The code below shows the use of token based security but you may consider using OAuth authentication
try
{
// exception will be thrown here if bad credential ...
var cred = await Esri.ArcGISRuntime.Security.IdentityManager.Current.GenerateCredentialAsync(
PORTAL_SERVER_URL, UserTextBox.Text, PasswordTextBox.Password);
// add the credential if it was generated successfully
Esri.ArcGISRuntime.Security.IdentityManager.Current.AddCredential(cred);
// identity manager will automatically include an available credential when connecting (based on the server URL)
_portal = await Esri.ArcGISRuntime.Portal.ArcGISPortal.CreateAsync(new Uri(PORTAL_SERVER_URL));
}
catch(ArcGISWebException webExp)
{
var msg = "Could not log in. Please check credentials. Error code: " + webExp.Code;
var messageDlg = new MessageDialog(msg);
await messageDlg.ShowAsync();
}
// once connected, get the license info from the portal for the current user
var licenseInfo = _portal.ArcGISPortalInfo.LicenseInfo;
3. If you saved the license information on local storage, your app can be started in an offline environment. You need to
license your app with the following code:
try
{
// set the client ID and initialize the ArcGIS Runtime
Esri.ArcGISRuntime.ArcGISRuntimeEnvironment.ClientId = "mYcLieNTid";
Esri.ArcGISRuntime.ArcGISRuntimeEnvironment.Initialize();
}
catch (Exception ex)
{
Console.WriteLine("Unable to initialize the ArcGIS Runtime with the provided client ID: " + ex.Message);
}
try
{
// read the saved license string from a local source (file on disk, e.g.)
var licenseJSON = this.GetSavedLicenseString();
The saved license information will allow your app to be used offline for a period of 30 days, after which the license
information will expire. The app must reconnect to ArcGIS Online or Portal for ArcGIS for new license information to be
obtained and a new 30 day period to start. If an app attempts to use expired license information, it will only function with
Basic level functionality.
Your app is now licensed for deployment with Standard functionality, including Local Server. Local Server extensions are however not
available for named users of ArcGIS Online or Portal for ArcGIS. You can only use these extensions with a license code, as described
below.
Steps:
1. Obtain and set the client ID for your app by following all of the Basic level licensing steps.
2. Obtain a license code by contacting the Esri office that serves you. You can also obtain a client ID from this Esri office if
you don't have access to an ArcGIS for Developers account. If you're in the United States, call Esri at 1-800-447-9778.
Note that each Extension license is a separate license code. To use an Extension license you must have a Standard
license.
3. Using the following code sample, set the license code in your app after you set the client ID and before any ArcGIS
Runtime functionality is used:
try
{
// set the client ID and initialize the ArcGIS Runtime
Esri.ArcGISRuntime.ArcGISRuntimeEnvironment.ClientId = "mYcLieNTid";
Esri.ArcGISRuntime.ArcGISRuntimeEnvironment.Initialize();
}
catch (Exception ex)
{
Console.WriteLine("Unable to initialize the ArcGIS Runtime with the provided client ID: " + ex.Message);
}
try
{
// use the license code to enable standard level functionality
Esri.ArcGISRuntime.ArcGISRuntimeEnvironment.License.SetLicense("runtimestandard,101,rux00000,none,XXXXXXX");
}
catch (Esri.ArcGISRuntime.LicenseException ex)
{
Console.WriteLine("Unable to license the ArcGIS Runtime with the license string provided: " + ex.Message);
}
4. If your app requires functionality provided by Local Server extensions, you'll need to specify their licenses as the second
parameter of the SetLicense method. The following example shows a license code being applied (first argument)
followed by codes for all extensions:
Esri.ArcGISRuntime.ArcGISRuntimeEnvironment.License.SetLicense(
"runtimestandard,101,rux00000,none, XXXXXXX",
"runtimespatial,101,rux00000,none, XXXXXXX",
"runtimenetwork,101,rux00000,none, XXXXXXX",
"runtime3d,101,rux00000,none, XXXXXXX");
Your app will now function offline or online with Standard functionality, including any Local Server extensions youve provided license
codes for, without any time limitations.
Related Topics
Deploy an app
Create an ArcGIS Runtime deployment
Deploy an app
Apps built with ArcGIS Runtime SDK for .NET can be deployed to your users by uploading your app package to the Windows Store, or
by sideloading it directly onto a device. In either case, you'll need to prepare your app for deployment and test it on real devices to ensure
a quality experience before putting it in the hands of your users.
The following broad steps are required to prepare your app for deployment:
1. License your app.
2. Add attribution.
3. Create a deployment of ArcGIS Runtime (for the platforms you want to support).
4. Deploy to a device for testing
Note: Deployment steps differ for each platform in the ArcGIS Runtime SDK for .NET (Windows Desktop,
Windows Store, and Windows Phone). Please consult the deployment information for each platform you
want to deploy.
License your app
Before creating a deployment, you must ensure that your app includes logic to apply the proper licensing for the functionality it provides.
Consult the License your app topic for licensing requirements and instructions.
Note: There is no need to license your app when deploying to devices for testing. You can deploy your app for
testing using a developer license.
Add attribution
You are required to attribute Esri in your Windows Store app according to the following guidelines.
ArcGIS Runtime SDK for .NETAbout and Credit screens must include the following text: Mapping API provided by Esri
ArcGIS Runtime SDK for .NET.
Map dataAll map data used in an application must be attributed in the About and Credit screens using the Copyright Text
section of the REST endpoint or endpoints being used. For example, ESRI_Imagery_World_2D service must use Copyright:
2009 ESRI, i-cubed, GeoEye.
Esri logoIf your application uses data served by Esri through ArcGIS Online, display a logo on the map pursuant to the logo
guidelines below. Examples of such data can be found on the ArcGIS Online maps page.
Note: When using Bing Maps in your application, it's important to include the proper attribution information. See
the Branding Guidelines from Microsoft for more information.
Steps:
1. Ensure that you have satisfied the prerequisites described on the Windows Store apps Dev Center.
2. Open the project for the app you want to deploy in Visual Studio.
3. In the Visual Studio Configuration Manager dialog box for your project, specify the Platform for your deployment (x86,
x64, or ARM).
4. Build your project.
5. From the Project menu, choose Store > Create app packages. Choose No when prompted to create a package to upload
A new app package is created in the folder you specified in the wizard. Everything needed to run the app is included in the
package. The following image shows the contents for a typical app package output folder.
The app package is the file with an *.appx extension. This is an archive file that contains the required files for your app. To
view its contents, you can change the extension to *.zip and open it in Windows Explorer. Inside, you'll find your app's
executable, the ArcGIS Runtime assembly, and an ArcGIS Runtime deployment folder (if you created one). The output folder
also contains a *.cer file, which is the developer's certificate that was used to sign the app package, and a PowerShell script
(*.ps1) that can be used to install the package on the target device.
6. Copy the deployment folder (not just the *.appx file) to the target device.
7. Open the folder on the device and run the PowerShell script (*.ps1). The script will guide you through installing the app.
8. When the installation is complete, you can launch the app from the WIndows 8 Apps menu for testing.
Note: Consult the System requirements topic for the supported target machine
requirements.
For more information about sideloading Windows Store apps, consult the following links:
How do I deploy an Windows 8 app to another device for testing?
Try it out: Sideload Windows Store apps
Sideloading Store apps to Windows 8.1 devices
Related Topics
License your app
Create an ArcGIS Runtime deployment
Note: Deployment steps differ for each platform in ArcGIS Runtime SDK for .NET (Windows Desktop, Windows
Store, and Windows Phone). Consult the deployment information for each platform you want to deploy.
The ArcGIS Runtime API for Windows Phone and Store does not use the developer installation but automatically includes the core ArcGIS
Runtime components as soon as a project is built in the location specified by the Output path property of the project.
The following image shows the options available in the deployment manifest designer. Because Visual Studio handles including ArcGIS
Runtime in the app package, it is not listed as an option in the manifest.
It is not necessary to use the ArcGIS Runtime deployment unless you want to display specialized symbology in your app that is referenced
by the ArcGISRuntimeEnvironment.SymbolsPath property. To display specialized symbology in your app, you will need to include
the symbol sets in your deployment using the deployment manifest file. Once you have specified the symbology required and built the
project, the deployment creates a folder named arcgisruntime<version> with a resources folder containing all the specialized symbol
sets.
You will require an ArcGIS Runtime deployment for every target platform. The deployment manifest file will automatically detect the
current platform target of each project in which it is included and build an ArcGIS Runtime with the appropriate architecture. This can be
one or more of x86 (32 bit), x64 (64 bit), any CPU, or ARM depending on your app type.
Note: The platform target is a property of your project and is modified in the Project properties designer or the
Solution Configuration Manager dialog box. The deployment manifest shows you the current setting, but it
does not provide a tool that allows you to change it.
You can update a deployment from a previous version (a project in which the manifest file version preceeds the extension SDK version,
in other words) using the existing deployment manifest file. Upon building your project, a deployment for the previous SDK version will
be generated (the same version as the manifest file).
You cannot, however, update your application deployment with an older manifest file if you change the referenced ArcGIS Runtime
assemblies to a newer version. To upgrade such a deployment, delete the existing deployment manifest file, update your SDK
references, add a new deployment manifest, and recreate the required settings.
Note: The menu item for adding an ArcGIS Runtime Deployment Manifest is not available in the Express editions
of Visual Studio.
1. Open the project or solution for your ArcGIS Runtime app in Visual Studio.
2. Right-click the project listing in the Solution Explorer window and choose Add ArcGIS Runtime .NET Deployment Manifest. This
adds a file to your project, named Deployment.arcgisruntimemanifest.
3. Access the manifest editor by double-clicking the manifest file or right-clicking the manifest file and choosing Open.
4. Click Yes if Visual Studio asks if you want to update and save the project.
You will then get a file modification warning as the ArcGIS Runtime deployment build extensions make changes to the project file.
Click Reload.
5. If the manifest is included in multiple projects, choose the target project from the list.
6. Choose required ArcGIS Runtime components for capabilities you have included in the app you want to deploy.
7. After choosing all required components, view the estimated deployment size.
8. Build the project.
9. When you build your project, an ArcGIS Runtime deployment will be created in the project's output location.
The deployment folder contains a resources folder with a symbols subfolder that contains the specific symbol sets you chose.
10. After building your project, create a package for your app (click Project menu > Store > Create app packages). The app
package will include your ArcGIS Runtime deployment. To test your app package, you can sideload your app onto a device
following instructions provided in this Microsoft article: Sideload Windows Store apps.
Option Description
Specialized Symbology Additional symbol sets required by your app.
Military (MIL2525C) Supports the handling and display of military messages using a MIL-STD-2525C-based symbol dictionary.
Military (App6B) Supports the handling and display of military messages using an App6B symbol dictionary.
Hydrographic (S57) Supports the handling and display of S57 data.
Related Topics
License your app
Deploy an app
Design considerations
When youre starting to build an app, consider the following:
The type of app to buildBecause you're reading an ArcGIS Runtime SDK guide right now, most likely it will be a native app. But
you can review the advantages and disadvantages to each type of appnative, hybrid, and web in Native vs. web.
The type of location-based app to build and how it should be presented to your usersDetermine your app/map pattern discusses
the main location-based app patterns and how they can affect the overall design of your app.
The main UI design elements of a mapping appProvide map tools discusses tools and map interactions. It's designed to get you
started quickly, especially if youre an advanced developer new to GIS or a GIS developer new to delivering apps.
Online or offlineIf your users will be working without an Internet connection, determine what capabilities will be supported offline.
For details, see Create an offline map.
The costs associated with licensing and deploying your appFor details, see Deploy your app.
Related Topics
Determine your app/map pattern
Provide map tools
Performance considerations
Native vs. web
Mapping apps
Maps can be added to an app for different reasons. It is the context in which the map is used that determines how it should appear and
behave in the app, which, in turn, is determined by what your users need.
Map-centric apps
In map-centric apps, the map is the most important thing about the app. Usually the map opens first and is the focus of the app.
Examples include the ArcGIS App and Collector for ArcGIS. The user gets value out of the app by interacting with the map; it's the map
that provides the desired intelligence or information.
Many of these apps open only one map or allow the user to choose from a few maps that are important to them. Users interact with the
same map for some time.
An example of this type of app is one that allows field workers to:
View their organization's assets in relation to their current location.
Determine the route and time it will take to get to the asset.
The value to the user is the map itself.
App start-up
In these apps, it's imperative that users get to the map as quickly as possible every time they start the app. Re-opening the last map
they were looking at is usually good practice. To do this, store information about the map (and its state, if desired) on disk so it can be
retrieved when the app restarts.
The form factor of the device will also affect how the map is presented. Map-centric apps will take over the entire screen of devices
such as tablets and phones, whether in portrait or landscape. However, on tablets in landscape mode or on desktops, there may be
enough screen real estate to incorporate side panels that contain information about the map. Some apps restrict the screen
orientation to ensure a good user experience. For example, an app may restrict phones to portrait because in landscape, the map is
too small and getting to the tools too difficult. Consider carefully what the user needs to do and whether they get usability benefits
from using the app in the different orientations.
If you do support multiple screen orientations and sizes, you should make sure that you optimize the design for each of those that you
support. This may mean designing specific screen layouts for the different options. You may also have to consider what happens
when a user turns the device from one orientation to another.
Cartography
The cartography of the map is also important. Full cartography recommendations are outside the scope of this topic, but many
resources are available to help you make maps like professional cartographers do, such as the Esri Mapping Center. In general, use
appropriate symbols that make sense to the user without having to look at a legend. Ensure layers are visible at appropriate scales.
Using scale dependency settings not only provides the right information at the right time (scale), but it also can improve performance.
Also ensure that colors of symbols and the commonly used basemap in your app work well together.
Tools
Be aware of the tools your apps expose. Your default tools should be the most commonly used, and they should be provided to the
user in an appropriate way for the platform and form factor your app is running on. For tips on appropriate use of tools, see Provide
mapping tools.
Map-as-navigation apps
In maps-as-navigation apps, the map is important, but it's not the most important part of the app. The map in this case drives the
navigation of the app and lets the user discover additional information and access other screens that provide value to the user. From the
user's point of view, the map itself has little value in this app; it's a tool to get to the information they need.
The toolset associated with the map should be focused, as the user will not be performing many additional map functions unless it
allows them to get to the target information more quickly or add some value to the information they receive. Often a drawing or selection
tool is appropriate to allow users to quickly draw their area of interest as a graphic on the map. The resulting graphic is then used to
query information (in the form of a QueryTask or query on a layer in the map). It's possible to query for information as the graphic is
being drawn to provide instant feedback, although the performance considerations of this should be evaluated. The use of
geoprocessing to retrieve data and provide information can also be used in this scenario.
Cartography is typically important, as the map should be simple and allow the user to select the areas or features that will display the
information of interest without any distractions. Consider which basemap you should use in this scenario.
An example of this type of app is one that allows users to define areas on the map that show what properties are for sale, what school
districts the properties are in, and what the average sales price is. The valuable content for the user is not the map, but the resulting
information. However, without the map, the user is unable to get to the target information.
Pop-ups can be used to display information based on features in the map. These are UI components that are provided in the SDKs that
allow you to build rich user experiences through map configuration rather than code.
Map-as-context apps
In a map-as-context app, the map is an additional or auxiliary view in the app and is mainly used for contextual purposes. The map is
created and shown based on some other source information also visible in the app. The map displays additional information, which the
user can choose to consider. The map is typically auto-populated with the correct layers, layer filters (also called layer definitions),
location, and zoom level specifically based on the source information.
In this case, map tools should be limited. In many cases, there should be no map tools, and the source information actually navigates or
changes the map. This requires binding the map's behavior to other view controls or elements that hold the source information and can
provide for an intuitive user experience, especially for those users who are not used to working with map interfaces.
Again, cartography is important for this scenario, as there should be few distractions on the map.
An example of this scenario is displaying a weather map for a specific location and time. The source information in this case is the
location name, the time of day, and the weather forecast for that area (temperature, wind speed, humidity, and so on). Initially, the map
shows additional weather information (cloud cover and rain radar for example) for the location and its surroundings at the time that is
being displayed. If the user changes the time of day, the map updates to show the weather information for the new time. The information
the user wants to know is the weather forecast (the source information); the map in this case is additional contextual information that
adds value to the source information. A map can be useful in this scenario, for example, when the source data shows the location will
have clear skies at 1:00 p.m., but the map shows a rain cloud nearby, at 2:00 p.m. the forecast is still sunny but the rain cloud is closer,
the user now knows a rain cloud is heading in their direction.
Mapless apps
Mapless apps that contain location-based intelligence are common and valuable, especially in devices that leverage GPS and motion
sensors to provide information to users. In this pattern, the user should never know about GIS, spatial intelligence, or mapping, and you
should choose your tool names and information screens carefully to hide these from the user.
Any spatial tasks that are run in these apps are run in the background and should not interrupt the user's flow. This typically requires
asynchronous development for tasks to run on background threads (not on the UI thread).
Some of these mapless apps (as well as many mapping apps) may require local data to be on the device. To achieve this, you can use
services, or you can provision the device with the data. For details on how to retrieve and access offline data (whether using a map or
not), see Create an offline map.
ArcGIS Runtime SDKs have many functions, described in the following bullets, that can help you build a mapless app.
Related Topics
Design considerations
Provide map tools
Performance considerations
Native vs. web
Map interactions
Think about how your users will want to interact with the map. Older applications required you to pick a particular tool on a toolbar to pan,
zoom in, zoom out, or view the full extent. With touch screens, mouse devices, and trackpads, many of these tools can be provided
through gestures, removing the need for tools on a tool bar altogether. In addition, the proliferation of devices that can provide their own
location based on GPS or other technique means that you can use this information to change the map's extent without the user doing
anything.
ArcGIS Runtime SDKs provide many of these interactions for you out of the box. But you still need to consider whether they're suitable for
your app. What will the user expect to happen when they touch the map? Will they be able to use two fingers to pinch and spread the map
(are they wearing gloves for instance)? Will they know to try a long press, double-tap, and a left/right swipe to open the search tool? For
answers to questions similar to these, see the section Understand your users and their surrounding environment.
Gestures
ArcGIS Runtime SDKs provide many gestures out of the box. Gestures aren't the answer to everything, but if you keep things simple,
intuitive, and follow the device's standard practices, you can provide a lot of functionality in your mapping app without a toolbar.
Display information
Once you've built some default map interactions or gesture-based tools, the next step is to display some information to the user. You can
turn complex data into rich, decision-making information for your users. If you understand your users and know what they want to achieve,
displaying the right information in an appropriate way can reduce the need for additional tools. Older GIS applications have displayed
tables and rows of data to the user, but modern approaches are more intuitive and powerful.
ArcGIS Runtime SDKs provide several API components to display information:
GraphicsArcGIS Runtime SDKs provide a graphics layer. Graphics layers allow you to add, to a map, graphics (points, lines,
polygons, or text) that can be associated with a symbol to make the graphics look the way you want. Graphics let you provide a lot
of information to users about something they have tapped on or an area they're interested in. However, you might need a legend
or additional information to allow the user to interpret what you've added. For details on graphics layers, see Add graphics and
text.
CalloutsA callout is a small view that displays on top of the map and has a leader that can point to a feature on the map. You
can use these effectively as long as you have enough screen real estate. You can embed text, images, and other items in these
callouts to provide information. The callout can be considered part of the map as it is tied to a specific geographic location and
therefore it moves as the map is panned or zoomed.
Pop-ups, supported throughout the ArcGIS platform, are a powerful way to bring your maps to life. ArcGIS Runtime SDKs fully
support pop-up configurations and provide you with views to display their content without having to write any of the UI code
yourself.
Platform-specific viewsFor native apps, there's a wide array of platform-specific views, widgets, and graphical layouts you can
use to display information, such as graphs, pie charts, meters, categorized text, and so on.
Contextual actions
When you want to provide non-gesture based functionality or tools for your users, you want to ensure they appear at the right place at the
right time. They dont always need to be executed from a toolbar.
For instance, let's say that a default map interaction of a long press adds a feature to the map and displays a list of actions or tools that
can be performed on the location like viewing more details, zooming, or finding directions to the location. You can change these actions or
tools based on the type of location the user pressed. This approach is typically better than exposing these actions on a toolbar, as they
would be active only after a location had been selectedthey might be greyed out most of the time, taking up valuable screen real estate
and confusing the user as to when they can be used.
For capabilities that may be hidden, such as a long press in a blank area of the map as a way to add a feature, it is recommended you add
in-app help. For example, to ensure the user knows that a long press adds a feature, when the user first opens the app, you could have an
image of a finger "fly in" from the right, then animate it to mimic the adding of a feature, with a dismiss control the user can press once he
understands the message being conveyed.
With contextual actions, you need to provide a clear exit path for the user, so they can return to where they came from. Use your target
platform's best practice and navigation tools to provide this behavior.
Toolbars
Not everything can be done without a toolbar. If your app requires a toolbar, make sure you plan out where the tools will display and how
the user will access or interact with them. You have many options to consider here, some of which depend on the platform and form factor
of the devices youre targeting.
Tools on a toolbar
Android has explicit design guidelines for adding tools to a toolbar (or ActionBar, in Android's case) that are relevant to all platforms.
Essentially, tools should be visible if they adhere to the FIT scheme (frequently used, important, and/or typical). If you are adding tools
to your toolbar try to adhere to this guidance. Cluttered toolbars make it difficult for users to find what they are looking for.
Hidden toolbars
Another approach is to provide the user with toolbars or menus that are viewable only through a gesture or button click. This allows a
number of tools to be shown at once but without them cluttering up the app's interface at all times. Patterns in use for hidden toolbars
include the following:
Slide out drawersMenus or tools display from the side of the screen via a gesture or a button click. Lots of apps are using this
approach so that commonly used tools don't clutter the app's screen real estate. The tools are easy for the user to show at any
time and can provide a long list of scrollable menus or tools. Most apps use menu items with clear text and icons so the user
knows exactly what will happen when these are pressed.
Tool wheelMenus and tools display in a wheel shape via a gesture or button click. This approach is more commonly used for
showing multiple tool buttons (typically without accompanying text) rather than menus. Like the slide out drawers, this approach
provides quick access to a number of tools for the user to quickly switch between. It's been used in apps for advanced drawing
to allow users to quickly switch between the vast array of draw tools. It's also been used in camera apps, whfere the user needs
to quickly pick the right setting to take pictures.
Related Topics
Design considerations
Determine your app/map pattern
Performance considerations
Native vs. web
Performance considerations
Hardware specifications, choices within your application development environment, and the ArcGIS Runtime each contribute to how well
your application will perform. You should consider each of these when trying to improve performance.
ArcGIS Runtime
The Runtime SDKs are built to be fast, but there are still ways you can improve performance by working with the items described below,
such as spatial reference and rendering modes.
Note: A video presentation of this topic's information is available, Squeezing every ounce of performance from
ArcGIS Runtime.
Spatial reference
When working with online services, it's important to choose the spatial reference for your map early and ensure data and layers are
stored, managed, and shared in the same spatial reference. This practice lets you avoid having data be reprojected on the server.
Reprojecting data is detrimental to performance.
Layers
As the topic Layer Types describes, multiple types of layers are available in the API depending on the content you want to display in the
map. Each type of layer has specific functional characteristics that determine the appropriate layer type for your content. With those
characteristics also come a set of performance characteristics you must consider when designing your map.
Another factor to consider is the number of layers in the map. This is typically expected to be in the range of 1s and 10s of layers. The
precise number of layers that can be added to the map while still being able to meet the performance expectations of your users is not a
simple calculation, because it depends on many factors. Some of these factors involve the performance characteristics mentioned
earlier. Other factors are noted in this topic, such as the volume of information in a layer and the way in which you symbolize the layer.
Additionally, the processor speed, memory, and graphics hardware resources of the device, or devices, on which you intend to deploy
the application significantly affect the application performance.
Adhering to these groupings allows the Runtime to optimize data transfer to the GPU. When layers with static rendering mode are
rendered to an image on the CPU, the Runtime can stack the images for multiple adjacent layers together and push the stack as a
single set of textures to the GPU. In contrast, when static layers are not adjacent to one another, the Runtime must generate multiple
images to preserve graphics' visibility ordering. In this case, multiple sets of textures must be pushed for each extent change. Layer
order does not affect layers rendering in dynamic mode because all resources for the layers reside on the GPU, and the GPU can easily
arrange these items when drawing.
Number of graphics
Many variables are at play when it comes to the number of graphics that can be rendered quickly on the map. The major factors to
consider are:
The complexity of the graphics (large numbers of vertices)
The target device
The mode you use (dynamic or static)
The end-user experience
In dynamic mode, graphics are constantly rendered, giving the map a seamless look and feel when interacting with it. The entire graphic
representation resides on the GPU, so as the number of graphics increases, the GPU has to work harder to render. A large number of
graphics can impact how responsive the map is to user interaction.
Static mode renders graphics when needed (when the map extent changes) and offloads a significant portion of the graphical
processing onto the CPU. As a result, less work is required by the GPU to draw the graphics, and the GPU can spend its resources on
allowing the map UI to remain interactive. However, heavy use of the CPU can impact battery life on a device.
Adding graphics
You can add graphics individually to the graphic collection on a graphics layer, or you can add graphics in bulk. The Runtime has
optimization checks on bulk additions for creating new textures for unique graphics and only pushes those textures to the GPU once.
This optimization typically makes adding graphics two to five times faster.
Symbolizing graphics
Graphics within graphics layers can be symbolized with either symbols or renderers. For graphics layers with small numbers of
graphics, it's acceptable to assign an individual symbol to each graphic. The Runtime will attempt to reuse duplicate symbols where it
can, but there is an overhead in this calculation.
For larger numbers of graphics, you should always use a renderer, which ensures the reuse of symbol instances. Another benefit of
using renderers is the efficiency related to adding new graphics. Since symbols are defined on the renderer, the API has less data to
push to the Runtime. Individual graphics can have symbols assigned even when the layer also has a renderer. In this scenario, the
symbol typically takes precedence, although in some cases, it's possible to control this behavior via the API. For more information on
symbols and renderers, see Symbols and renderers.
Renderers
Graphics layers can have both symbols and renderers assigned to them. For graphics layers with small numbers of graphics, it's
acceptable to use individual symbols on each graphic. The Runtime will attempt to reuse duplicate symbols where it can, but there's an
overhead in this calculation.
For larger numbers of graphics, you should always use a renderer, where unique symbol reuse is ensured. Another benefit of using a
renderer is the efficiency related to adding new graphics. Since symbols are defined on the renderer, the API can push less data to the
Runtime.
Scale range
You can improve performance by rendering only the graphics that make sense for a scale range and turn off the graphics that don't. You
do this by setting a scale range on a layer to indicate at which scales (zoom level range) you want that layer to display. For example,
when your user zooms out to a country boundary, you can have the detailed bus routes layer turn off automatically.
Setting this scale range, also known as setting scale dependency, not only makes the map less cluttered and easier to use, but it also
conserves GPU (in dynamic mode) and CPU (in static mode) resources, because unneeded graphics aren't rendered.
Additional resources
A video presentation of this topic's information is available, Squeezing every ounce of performance from ArcGIS Runtime.
Maps and layersDescribes layer types and includes information on how they relate to performance.
Asynchronous programming
On mobile devices where you have limited resources and variable network speed it is advisable to perform long running tasks on a
background thread.
However, since threads consume device resources, you still do need to pay particular attention to minimizing the amount of threads that
are created. See the Asynchronous programming and Threading considerations topics for more details.
Hardware
Hardware is designed with functionality and specific needs in mind. Be sure to understand the capabilities of your hardware before adding
the complexities of an application environment and the ArcGIS Runtime to your requirements.
Device limitations
Mobile devices have less processor and memory resources compared to standard desktop machines. For this reason, applications need
to be developed to run in an efficient manner.
Network speed
Mobile devices often use 3G or sometimes lower speed radio communication networks to obtain and transfer data. The speed of these
networks vary but are much slower (in terms of data per second) than wired or wireless networks. Due to this network latency, small
requests can take time to return, which makes your application seem sluggish. Therefore, you need to carefully manage the total
amount of data and the number of network requests submitted by your mobile application. As an example, it may be more efficient to
send a single large request for data rather than multiple small requests. Changing the layer types, application functions, or the flow of
your application can also affect network speed.
If your mobile application users are always in the range of a wireless network, your application can retrieve and submit larger amounts
of data. However, even in this scenario, it's always good practice to remember the amount of data and number of requests your
application uses, whatever the bandwidth.
By understanding the characteristics of the different types of map layers in the API, you can determine the best layers for your needs
and ensure that your application performs for your users.
Network connectivity
Some application users may only have intermittent network access, such as intermittent 3G access due to working in remote areas or
daily access to a wireless network for synchronizing data. If this is the case, local storage usage is important. The application can be
designed to connect to the server to retrieve data the user needs, then store this data on disk or in a local SQLite database.
Applications need to be developed robustly with this in mind, because the network connection can be dropped anytime. Functions need
to fail gracefully, and any long running application transactions may need to be rolled back.
Related Topics
Design considerations
Determine your app/map pattern
Provide map tools
Native vs. web
Related Topics
Design considerations
Determine your app/map pattern
Provide map tools
Performance considerations
New functionality
The 10.2.7 release includes enhancements to 3D mapping that provide a better scene interaction experience for the user, more efficient
tile and surface rendering, and improved label display. New network analysis tasks have been added for determining service areas and
closest facilities along a network, and several improvements have been made to KML layers. The following lists improvements and new
functionality for this release.
3D mapping improvements
Depth based scene navigation
Better calculation of mouse/touch location in three dimensions
Smooth navigation towards the surface, buildings, or objects under the mouse/touch location
Accurate navigation relative to objects in a scene (buildings, for example) and navigating around these objects is now
possible
Interactive navigation options (see the Scene navigation topic for details)
Enable or disable keyboard, mouse, touch, or stylus input
Set mouse wheel direction for zooming in/out
Set zoom factor and flick inertia
Tile rendering and elevation improvements
More efficient management of imagery resources for tiles and terrain/elevation data
Optimized tile rendering
Reduced memory usage
Atmospheric effects: Enable basic or realistic atmosphere representation
Labeling
Fade in/out of label display
Label alignment adjusts during navigation
Resolution of label conflicts for increased readability
KML: Support for extrusion, altitude modes, and model symbols
New network analysis tasks
Service area task: Calculate service area polygons for a set of facilities on a network
Closest facility task: Determine routes from points on a network to the closest facility
Others
Support for developing with Visual Studio 2015 and Blend 2015
GeodatabaseSyncTask.Unregister is overloaded to accept a replica ID (string) rather than the full Geodatabase object
KML enhancements, including Network Link and improved authentication handling.
Bug fixes
In addition to addressing overall quality and the new functionality added to the APIs, the following bugs have been fixed with the 10.2.7
release.
Layers in a Scene do not display correctly around the poles.
A search for features from an ArcGIS for Server 10.3 service using FindTask.ExecuteAsync does not honor a value of true
for FindParameters.Contains. This prevents searching for anything but exact matches of the find string from those services.
BUG-000084840 MrSID raster imagery added via the DynamicLayer endpoint displays with higher than normal brightness.
BUG-000087473 GeodatabaseFeatureTable.QueryRelatedAsync throws SEHException.
BUG-000090122 DynamicLayerInfo min/max scales are not honored when rendering a DynamicLayer in WGS84.
BUG-000090189 LocalLocatorTask fails to initialize when the path to the locator contains multi-byte characters.
BUG-000090851 Rapid zooms or pans on a MapView containing layers from a .geodatabase file may produce an access violation
error.
BUG-000091175 LocalServer fails to start the LocalMapService when loading a map package that uses third party fonts.
ShapeFileTable.OpenAsync fails with custom SR PRJ file citing Invalid argument : wkt.size() == 0 (GeoNet)
GraphicsLayer labels do not display on the MapView when the layer RenderingMode is Static (GeoNet).
Store app may freeze when loading layers with labels from local geodatabase (GeoNet).
Known limitations
The following list describes known limitations or issues with the 10.2.7 release. Where one is available, a workaround is described.
Note: Several graphic issues are specific to the graphic layer rendering mode. The implied workaround for these
issues is to change the rendering mode (if practical for your use case). See the Rendering modes topic for
more information about choosing the rendering mode for a GraphicsLayer or GraphicsOverlay.
Windows 8.0 is no longer supported as an app development or deployment platform with the 10.2.7 release. For more information
please see: Deprecation Plan for ArcGIS
[3D] A scene does not use the extent of the base layer to define an initial view. This contrasts with the behavior of the map.
Workaround: Handle the LayerLoaded event for the Scene control and set the initial view to focus on the layer.
private void MySceneView_LayerLoaded(object sender, Esri.ArcGISRuntime.Controls.LayerLoadedEventArgs e)
{
if (e.LoadError == null && e.Layer.ID == "MyLayer")
{
var initialViewpoint = new ViewpointExtent(e.Layer.FullExtent);
var animationDuration = TimeSpan.FromSeconds(2);
MySceneView.SetViewAsync(initialViewpoint, animationDuration);
}
}
PictureFillSymbol.Angle and PictureFillSymbol.Opacity properties are not honored for graphics displayed in a
MapView when the GraphicsLayer RenderingMode is Static.
[3D] PictureFillSymbol.Width and PictureFillSymbol.Height properties are not honored in a SceneView when the
image source is based on an absolute URL.
HydrographicS57Layer is not available in the Windows Phone API. This layer type is available for Windows Store and
Windows Desktop apps only at this release. We hope to make this available for Windows Phone in a future release.
[3D] Z values of Features from a feature service are not honored in a FeatureLayer displayed in a SceneView.
Workaround: Query the feature service with ReturnZ = true and display the results in a GraphicsLayer with the
desired elevation mode, as shown in the following example.
var queryTask = new QueryTask(new Uri("http://myserver/arcgis/rest/services/FlightPaths3D/FeatureServer/0"));
var query = new Query("1=1");
query.ReturnZ = true;
[3D] FeatureLayer layers displayed in a SceneView do not request additional features after exceeding the feature transfer limit
determined by the service, the equivalent of QueryMode.Snapshot. This contrasts with the MapView, where the layer may
request additional features as new extents are displayed (QueryMode.OnDemand).
Labels are not displayed for lines that share a vertex and have the same label value. While this is often the desired behavior (a
single label for a street rather than one for each segment that composes it, for example), there is no option to enable distinct labels
under those conditions.
[3D] Polyline graphics in a SceneView may suffer some display degradation during a SetViewAsync animation when the
RenderingMode is Static.
Sharing the same map instance simultaneously among two or more map views, or scene instance among multiple scene views, is
not supported and is likely to cause stability or performance issues. Similar issues are likely to be encountered when attempting to
share graphics overlays, layers, or distinct feature layer instances that share the same feature service (ServiceFeatureTable)
between multiple maps or scenes at the same time.
Workaround: if you need to reuse a Map or Scene in another view control, you should ensure that it is then removed from
the previous control. The same technique can be used for reusing a layer instance between maps and/or scenes, as
illustrated in the following example.
var layer = MyMapView1.Map.Layers["MyFeatureLayer"] as FeatureLayer;
Breaking changes
No breaking changes have been introduced with this release. For a detailed description of the changes between the previous (10.2.6) and
current (10.2.7) releases, see the Esri.ArcGISRuntime assembly comparison.
New functionality
The 10.2.6 release includes new classes to support 3D mapping, such as the SceneView and Scene controls. An online or local data
source can be used to define an elevation surface for your scene, and there are several options for displaying graphics relative to the
surface using a variety of 3D symbols and renderers. A new SceneLayer class enables you to consume a new 3D service type available
in ArcGIS for Server 10.3, called scene services. KML data can now also be consumed in your ArcGIS Runtime app (in a map or scene)
using the KmlLayer class.
Note: Several new topics have been added to the Developers Guide that describe 3D mapping in ArcGIS Runtime
SDK for .NET, including how to create a scene, navigate, add layers, and display 3D graphics.
The following enhancements have also been made.
ENH-000082926: Localize labels of MapGrid.
ENH-000086053: Expose a property to allow users to explore the map with a stylus.
AddAsync, UpdateAsync, and DeleteAsync methods on FeatureTable now accept IEnumerable<Feature>.
Bug fixes
In addition to addressing overall quality and the new functionality added to the APIs, the following bugs have been fixed with the 10.2.6
release.
BUG-000082908: Shifted position when changing the geometry of TextSymbol graphic with rending mode Static.
BUG-000083073: ArcGIS Runtime apps fail to execute when run within a directory that contains a multi-byte character.
BUG-000083158: Shapefile feature attributes look garbled when using a Shift-JIS encoding instead of UTF-8.
BUG-000083933: A LabelPosition setting of FixedPositionWithOverlaps is ignored after first draw.
BUG-000084223: Changing the MapView control position does not rerender the map and ignores any map changes.
BUG-000084521 / BUG-000084625: Editing a feature layer attribute which participates in a label definition on a feature service
causes a crash.
BUG-000084603: The ShapefileTable class is unable to read a shapefile in a Japanese name path.
BUG-000084624: A AttributeLabelClass with a TextExpression ignores the LabelPlacement value after updating
graphic attributes.
BUG-000084781: The ShapefileFeatureTable class reads date values incorrectly.
BUG-000084845: Unwanted white line when calling HitTest on a line symbol defined by CIM json.
BUG-000085172: Intermittent exceptions occur when updating graphic geometries on a very frequent basis.
BUG-000086359: An InvalidOperationException error occurs when syncing with a feature service which has versioned
data that supports per replica synchronization.
BUG-000086664 / BUG-000086665: Calling ServiceFeatureTable.ApplyEditsAsync with a large number of features
returns a task canceled exception.
Opening Geodatabase throws exception: "non-convertible value type in convert".
Reusing the MapView or Map control causes the map to freeze (Store/Phone only).
Setting MapView.MinScale in XAML has no effect.
Polylines from a runtime geodatabase do not renderer as expected.
Exception when removing layers and panning (Store/Phone only).
Known issues
The following list describes known issues or limitations with the 10.2.6 release. Where one is available, a workaround is described.
Note: Several graphic issues are specific to the graphic layer rendering mode. The implied workaround for these
issues is to change the rendering mode (if practical for your use case). See the Rendering modes topic for
more information about choosing the rendering mode for a GraphicsLayer or GraphicsOverlay.
HydrographicS57Layer is not available in the Windows Phone API. This layer type is available for Windows Store and
Windows Desktop apps only at this release. We hope to make this available for Windows Phone in a future release.
[3D] Graphics may not display correctly (may become distorted, in other words) when near the horizon.
Changes to an existing CompositeSymbol (adding, removing, or updating the symbols it contains) are not reflected in the
display.
Workaround: Recreate, modify, and re-apply the composite symbol as illustrated in the following example.
// create a new composite symbol
var newCompoiteSymbol = new CompositeSymbol();
// loop through all symbols in the existing composite symbol
foreach (Symbol s in oldCompositeSymbol.Symbols) {
// copy symbols from the existing composite symbol to the new one
newCompoiteSymbol.Symbols.Add(s);
}
Only fields containing string values are supported for use as the TemporalRenderer.TrackIdField.
[3D] Layers in a Scene do not display correctly around the poles.
[3D] GraphicsLayer in static rendering mode does not render picture symbols using a relative or absolute URI.
[Windows Phone] Loading large datasets can be memory intensive and may cause crashes on low memory devices. If your app
requires scenes, working with KML datasets that contain large amounts of data, and so on, you might consider disabling support
for low-memory phones.
[3D] Line styles for SimpleLineSymbol other than SimpleLineStyle.Solid are not honored on graphics in a Scene when
rendered in dynamic mode using absolute or relative placement.
Sharing the same map instance simultaneously among two or more map views, or scene instance among multiple scene views, is
not supported and is likely to cause stability or performance issues. Similar issues are likely to be encountered when attempting to
share graphics overlays, layers, or distinct feature layer instances that share the same feature service (ServiceFeatureTable)
between multiple maps or scenes at the same time.
Workaround: if you need to reuse a Map or Scene in another view control, you should ensure that it is then removed from
the previous control. The same technique can be used for reusing a layer instance between maps and/or scenes, as
illustrated in the following example.
var layer = MyMapView1.Map.Layers["MyFeatureLayer"] as FeatureLayer;
MyMapView2.Map.Layers.Add(layer); // add the layer to a new map
MyMapView1.Map.Layers.Remove(layer); // remove the layer from its original map
[3D] A scene does not use the extent of the base layer to define an initial view. This contrasts with the behavior of the map.
Workaround: Handle the LayerLoaded event for the Scene control and set the initial view to focus on the layer.
private void MySceneView_LayerLoaded(object sender, Esri.ArcGISRuntime.Controls.LayerLoadedEventArgs e)
{
if (e.LoadError == null && e.Layer.ID == "MyLayer")
{
var initialViewpoint = new ViewpointExtent(e.Layer.FullExtent);
var animationDuration = TimeSpan.FromSeconds(2);
MySceneView.SetViewAsync(initialViewpoint, animationDuration);
}
}
// get the 3D point passed to the SceneViewTapped event (with Z coordinate, in other words)
var dddPoint = e.Location;
// create a MapPointBuilder to edit the point
var pointBuilder = new Esri.ArcGISRuntime.Geometry.MapPointBuilder(dddPoint);
// create a new feature and set its geometry with the Z-less map point
newFeature.Geometry = pointWithoutZ;
Breaking changes
For a detailed description of the changes between the previous (10.2.5) and current (10.2.6) releases, see the Esri.ArcGISRuntime
assembly comparison.
The following properties have been removed.
Esri.ArcGISRuntime.ArcGISRuntimeEnvironment.UseTextureFonts
Esri.ArcGISRuntime.Controls.ViewBase.Editor
Note: This property is still available on the MapView control. It is no longer defined on the abstract
ViewBase base class.
Esri.ArcGISRuntime.Controls.ViewBase.InteractionOptions
Note: This property is still available on the MapView control. It is no longer defined on the abstract
ViewBase base class.
System requirements
Version 10.2.7 of ArcGIS Runtime SDK for .NET contains APIs to develop for Windows Desktop, Windows Store, and Windows Phone.
Each API has specific system requirements for your development machine as well as for the machines and devices to which you will
deploy your app.
Supported platforms
Windows 10 Home, Professional, Enterprise, and Educational (32 bit and 64 bit [EM64T])
Windows 8.1 Basic, Professional, and Enterprise (32 bit and 64 bit [EM64T])
* - Deployment to Windows 8.1 only
Supported IDEs
Visual Studio 2015 (all editions)
Visual Studio Express 2015 for Windows
Visual Studio 2013 (all editions)
Visual Studio Express 2013 for Windows
DirectX
ArcGIS Runtime SDK for .NET uses DirectX to provide high-performance map rendering. DirectX provides support for hardware and
software rendering of graphics, and is provided by the supported Windows platforms.
Direct3D feature level 9_3
Default: DirectX 11 hardware support
Falls back to DirectX 11 software rendering if hardware support is not available
Supported platforms
Windows 8.1
Supported platforms
Windows 8.1 Basic, Professional, and Enterprise (32 bit and 64 bit [EM64T])
Supported IDEs
Visual Studio 2013 (all editions)
Visual Studio Express 2013 for Windows
DirectX
ArcGIS Runtime SDK for .NET uses DirectX to provide high-performance map rendering. DirectX provides support for hardware and
software rendering of graphics, and is provided by the supported Windows platforms.
Direct3D feature level 9_3
Default: DirectX 11 hardware support
Falls back to DirectX 11 software rendering if hardware support is not available
Supported platforms
Windows 8.1
Essential vocabulary
analysis
A systematic examination of a problem that provides new information. ArcGIS Runtime SDKs support many types of analysis, from simple
geometry-based analysis to advanced spatial analysis. You can also string analysis operations together to build models for analysis. For
details on analysis and model building, see geoprocessing.
API
Application programming interface. A specification that allows developers to create applications.
basemap
A map layer that helps orient the user of the map. Typically it shows roads and buildings, is non-editable, and is a tiled layer. For a
description of basemaps and other layer types, see Layer types.
cache
For details, see tile cache.
Client ID
In ArcGIS Runtime SDKs, an identifier you associate with the app you build (one Client ID per app). You get a Client ID by signing into
developers.arcgis.com. For details, see License your app.
connected
In ArcGIS Runtime SDKs, the state of having a network connection to one or more of the following: ArcGIS for Server, Portal for ArcGIS,
or ArcGIS Online.
coordinate
A value that denotes the location of a vertex. Coordinates may represent 2D (x,y) or 3D (x,y,z) space. The meaning of the x,y,z-
coordinates is determined by a coordinate system. The vertices and coordinate system together allow your app to translate a real-world
object from its location on the Earth to its location on your map. For details, see Geometry contents in the Geometry operations topic.
coordinate system
A reference framework consisting of a set of points, lines, and/or surfaces, and a set of rules, used to define the positions of points in
space in two or three dimensions. For details, see Geometry contents in the Geometry operations topic. Also known as map projections.
deployment pack
In ArcGIS Runtime SDKs, a set of deployments for an app that contains Standard license level capabilities and does not require users to
sign in with their ArcGIS Online or Portal for ArcGIS organizational account. Each pack comes with at least one product license string.
Available licenses (license strings) are:
Standard
3D Analyst
Network Analyst
Spatial Analyst
For details, see the topics License your app and Deploy your app.
device
In ArcGIS Runtime SDKs, nearly any kind of computer, including desktops, mobile phones and devices, laptops, smartwatches, and large
mainframes.
disconnected
For details, see offline.
feature
A representation of a real-world object on a map, such as a building, a river, or a county. A feature may include attributes and a geometry .
For more information, see Features and graphics.
geodatabase feature
A representation of a real-world object persisted in a geodatabase. When displayed, it is displayed in a feature layer.
GeodatabaseFeatures can have geometry and attributes. GeodatabaseFeatures are associated with a feature table, with which they
share a common schema.
geometry
The combination of location and shape for a real-world object or for a geometric construct such as an area of interest or a buffer area
around an object. Geometry is the fundamental element for performing spatial analysis. For information on analysis operations such as
clip, buffer, and intersect, see Geometry operations.
GeoPackage
A single SQLite file (.gpkg) that conforms to OGC GeoPackage specification (http://www.opengeospatial.org/standards/geopackage) that
defines GeoPackages for direct use of vector geospatial features and/or tile matrix sets.
geometry
The combination of location and shape for a real-world object or for a geometric construct such as an area of interest or a buffer area
around an object. Geometry is the fundamental element for performing spatial analysis. For information on analysis operations such as
clip, buffer, and intersect, see Geometry operations.
geoprocessing
A GIS operation used to manipulate data. A typical geoprocessing operation takes an input dataset, performs an operation on that
dataset, and returns the result of the operation as an output dataset. Common geoprocessing operations include geographic feature
overlay, feature selection and analysis, topology processing, raster processing, and data conversion. Geoprocessing allows for definition,
management, and analysis of information used to form decisions.
You can use geoprocessing tools to chain together a sequence of operations, feeding the output of one tool into another tool, to automate
your work, solve complex problems, or perform batch processing. Sequencing operations like this are referred to as model building.
Your app can consume online geoprocessing services or local (packaged) geoprocessing tools. For details on which local tools are
supported in each license level, see Supported geoprocessing tools.
graphic
A representation of a real-world object stored in memory. When displayed, it is displayed in a graphics layer. Graphics exist while the app
is running, and therefore are used often for temporary features. Graphics can have geometry and attributes. Graphics are not associated
with a feature table. For more information, see Features and graphics.
license code
A string of characters that you add to your project, as described in License your app to unlock certain capabilities on the deployment
device.
local service
Services, such as geoprocessing services you create, used by your deployed application that are running on the same machine or device
as the application. Because they can consume local services, applications you build with ArcGIS Runtime SDK do not require an ArcGIS
Server connection to run or to access geodatabase data. Local services use packages. For details, see packages.
map cache
For details, see tile cache.
mobile app
In ArcGIS Runtime SDKs, a software application that operates on a mobile device. A mobile device is typically a mobile phone or tablet,
such as an iPhone, iPad, and an Android phone and tablet. Apps for custom-purpose handhelds, such as Windows Mobile devices, and
car navigation systems are not included unless otherwise specified.
mobile device
In ArcGIS Runtime SDKs, a mobile phone or tablet, such as an iPhone, iPad, and an Android phone and tablet. Custom-purpose
handheld devices, such as Windows Mobile devices, and car navigation systems are not included unless otherwise specified.
offline
In ArcGIS Runtime SDKs, the state of having no network connection to any of the following: ArcGIS for Server, ArcGIS Online, or Portal
for ArcGIS.
operational layer
A map layer that users can interact with. Typically, an operational layer is vector-based and is editable by users. However, it can also be
tiled data that can be queried against. See Maps and layers for more information.
package
A set of items, such as a map and its referenced data, that ArcGIS for Desktop bundles into a single file on your local machine so that the
items can be easily transfered from user to user or provisioned onto a device. Especially useful for disconnected apps.
renderer
A mechanism that defines how data appears when displayed. See Symbols and renderers for more information.
Runtime components
A collection of files containing various parts of ArcGIS Runtime functionality, installed and used on your development machine and
deployed with the apps that you create.
The full collection, installed to your development machine when you install ArcGIS Runtime SDK, includes the required Runtime core
components and optional components such as those for Local Server and advanced symbology. When you prepare an app for
deployment, the Deployment Builder tool helps ensure you deploy only the parts of the collection that are required by the app you build.
For descriptions of optional Runtime functionality sets, see Create an ArcGIS Runtime deployment.
Runtime core
Client files (.dll or .so) that must be deployed with all ArcGIS Runtime apps. For Java, Qt, and WPF, you can use the Deployment Builder
wizard to choose which Local Server capabilities you want to deploy so they can be bundled with the Runtime core files for you.
SDK
Software development kit. A collection of documentation, sample code, and sample apps to help a developer use an API to build apps.
shapefile
A vector data storage format for storing the location, shape, and attributes of geographic features. A shapefile is stored in a set of related
files.
side-by-side development
A capability that lets you develop with different versions of the same SDK on the same machine.
tile
An image, often a graphics file (for example, a .jpg file) and typically stored in a directory known as a cache. The image is part of a set of
tiles that, conceptually, are pieces of a bigger map. How the tiles fit into the bigger map, along with other information, is defined in a tiling
scheme. Two tile categories are:
Tiles in dynamic layers are created on-the-fly and can be stored in a cache on the client machine or on the server machine. Which
tiles are created in this scenario depends on where the user pans and zooms, so technically, the tiles may not make up a
complete bigger map when put together.
Tiles in tile cache layers are created before users view the map, often by a developer or GIS data administrator. These tiles are
known as pre-processed tiles.
Also see tile cache.
tile cache
A directory that contains tiles of a map extent at specific levels. The directory can be local to a desktop app or to a client app in a client/
server configuration. Also see tile.
tiled layer
A tiled layer is a layer comprised of images that when put together make up a bigger image of a map. Tiles are generated before they're
displayed for the user. This differs from a dynamic layer, which generates the images as they are requested by the user, or on-the-fly.
Tiled layers are often used for basemaps.
tile package
Tile packages (.tpk files) make is easy to share complete map documents with others. A tile package contains a map and the tile cache of
the data contained within it, packaged into one convenient, portable file. Tile packages can be used for easy sharing of cached maps
between colleagues in a workgroup, across departments in an organization, or with any other ArcGIS user using ArcGIS Online. Tile
packages are ideal in disconnected environments where access to local data is required.
toolkit
A set of user interface components to assist rapid application development. The toolkit components are contained in the toolkit assembly
for which the source code is available in a public GitHub repository.
vertex
A point that stands alone or makes up part of a geometry. Vertices that make up a geometry may be connected, one to the next, in a
linear order. For more information on vertices and how they're stored in geometries, see Geometry contents in the Geometry operations
topic.
viewshed
The locations visible from one or more specified points or lines. Viewshed maps are useful for such applications as finding well-exposed
places for communication towers, or hidden places for parking lots. You can create viewsheds using the Standard license level of ArcGIS
Runtime SDKs.
Related Topics
Spatial references
Related Topics
Spatial references
Supported languages
Language support in ArcGIS Runtime provides exception messages in the language of the computer running the app. The following
languages (cultures) are supported.
Arabic (ar)
Czech (cs)
Danish (da)
German (de)
Spanish (es)
Estonian (et)
Finnish (fi)
French (fr)
Hebrew (he)
Italian (it)
Japanese (jp)
Korean (ko)
Lithuanian (li)
Latvian (lv)
Norwegian (nb-NO)
Dutch (nl)
Polish (pl)
Portuguese (pt-BR, pt-PT)
Romanian (ro)
Russian (ru)
Swedish (sv)
Chinese (zh-CN, zh-Hans)
Legal
The following legal notices are installed in the legal subfolder of the ArcGIS Runtime SDK installation folder.
Copyright and Trademarks
Licensing Terms of Use (End User Licensing Agreement)
Acknowledgments of third parties whose software has been used in permissible forms with ArcGIS Runtime SDKs
For the latest versions of these documents and other legal information, see http://www.esri.com/legal.