Skip navigation
All Places > Developer Communities > Native App Developers > ArcGIS Runtime SDK for .NET > Blog
1 2 Previous Next

ArcGIS Runtime SDK for .NET

18 posts


In ArcGIS Runtime SDK for .NET 100.6 we added a useful API enhancement that can improve the performance of your apps with the new Esri.ArcGISRuntime.RuntimeCollection.AddRange method. There are several classes in the API that derive from the base RuntimeCollection, making this method available on many commonly used types such as GraphicCollection, GraphicsOverlayCollection, LayerCollection, UniqueValueCollection, and ClassBreakCollection.

 

The AddRange method helps improve performance for your apps by batching internal ArcGIS Runtime logic related to error handling and collection changed events. Internal benchmark tests run by the ArcGIS Runtime SDK for .NET development team using BenchmarkDotNet to compare individual GraphicCollection.Add calls with the GraphicCollection.AddRange call showed a 10-15% reduction in execution time when adding large numbers of Graphic instances to a GraphicCollection (i.e. GraphicsOverlay.Graphics). Additionally there was a 85-90% reduction in temporary allocations which reduces the memory consumed and reduces the workload for garbage collection. 

 

The two code snippets below show an example using the AddRange method, new at 100.6, and an example using the existing Add method.

 

AddRange method

 

GraphicsOverlay graphicsOverlay = new GraphicsOverlay();
graphicsOverlay.Renderer =
new SimpleRenderer(new SimpleMarkerSymbol(SimpleMarkerSymbolStyle.Circle,
  Color.CornflowerBlue, 10));
SpatialReference spatialReference = SpatialReferences.WebMercator;
Random random = new Random();
List<Graphic> graphicList = new List<Graphic>(10000);
for (int i = 0; i < 10000; i++)
{
Graphic graphic =
new Graphic(new MapPoint(random.Next(0, 20000000), random.Next(0, 20000000),
  spatialReference));
graphicList.Add(graphic);
}
graphicsOverlay.Graphics.AddRange(graphicList);

 

Add method

 

GraphicsOverlay graphicsOverlay = new GraphicsOverlay();
graphicsOverlay.Renderer =
new SimpleRenderer(new SimpleMarkerSymbol(SimpleMarkerSymbolStyle.Circle,
  Color.CornflowerBlue, 10));
SpatialReference spatialReference = SpatialReferences.WebMercator;
Random random = new Random();
for (int i = 0; i < 10000; i++)
{
Graphic graphic =
new Graphic(new MapPoint(random.Next(0, 20000000), random.Next(0, 20000000),
  spatialReference));
graphicsOverlay.Graphics.Add(graphic);
}

Symbol files are now available for improved diagnosis of issues when working with ArcGIS Runtime SDK for .NET.

 

Symbol files, or program database files (.pdb), link instructions in compiled applications and libraries to statements in the original source code. They enable you to access a more informative call stack if that application or library fails. Call stacks are valuable because they enable us to:

  • Identify if the issue you are experiencing matches an existing issue in our backlog
  • Determine if we have reproduced the same issue you have in your environment
  • Gain more insight on where to look for the underlying problem

 

If your WPF or UWP application crashes and the call stack points to the ArcGIS Runtime libraries, you can use either of the two workflows outlined below to provide Esri with more specific information and help us to more swiftly identify the cause of issue. 

 

When debugging and working with symbol files you will see a distinction made between managed and native libraries ("modules"). Managed modules contain code whose execution is managed by the .NET Common Language Runtime. Native modules contain code whose execution is controlled by the developer of that library and as such is often referred to as unmanaged code.

 

The UWP and WPF APIs within ArcGIS Runtime SDK for .NET each comprise one managed and two native libraries:

  • Esri.ArcGISRuntime.dll: A managed library containing the .NET API types you reference
  • RuntimeCoreNet.dll: A native library containing functional references to the ArcGIS RuntimeCore library
  • RuntimeCore.dll: A native library containing the implementation for all ArcGIS Runtime core capabilities

 

Add a reference to the Esri symbol server

  1. In Visual Studio, open the Options dialog (Tools > Options).
  2. In the Options dialog expand Debugging and choose Symbols.
  3. Click the ‘+’ button to add a new symbol file (.pdb) location.
  4. Enter the Esri symbol server URL: http://downloads2.esri.com/support/symbols.
  5. Ensure the checkbox is checked next to the new URL in the list of `Symbol file (.pdb) locations` and click `OK` to close the Options dialog.

 

Screen capture of Visual Studio Options Debugging Symbols dialog

 

For more information see Specify symbol (.pdb) and source files in the Visual Studio debugger in the Microsoft documentation.

 

Workflow 1. Debug the application

 

Follow these steps if you can reproduce the problem when running your application with the debugger attached.

 

  1. In Visual Studio, click `Start Debugging` (or tap F5).
  2. Open the Modules window by choose Debug on the menu bar > Windows > Modules.
  3. Locate the module Esri.ArcGISRuntime.dll then right click and choose `Load Symbols`.
  4. Ensure the `Symbol Status` for the module is `Symbols loaded`.
  5. Run through the workflow that reproduces the problem.
  6. Open the Threads window by choosing Debug on the menu bar > Windows > Threads.
  7. Locate and select the thread showing the current execution point (indicated by a yellow arrow).
  8. If the current execution thread shows no references to ArcGIS Runtime then locate the faulting thread.
  9. Inspect for references to ArcGIS Runtime.
  10. Select the thread of interest in the threads window.
  11. From the menu bar, navigate to Debug > Windows > Call Stack to view the call stack for the thread.
  12. In the Call Stack window, right click and choose Select All then copy the selected text.
  13. If you see one or more calls to Esri.ArcGISRuntime.dll with lines similar to runtimecore.dll!00007ffdeb571164 this indicates the call stack continues into the ArcGIS Runtime native libraries and you must enable native code debugging to get more information.

 

For more information see How to use the threads window in the Visual Studio documentation.

 

Enable native code debugging

 

  1. In Visual Studio, open the Project Properties dialog and select the Debug tab.
  2. Under the section `Debugger engines`, check the box to `Enable native code debugging`.

 

For more information see Enable mixed mode debugging in the Microsoft documentation.

 

Debug the application with native code debugging

 

  1. In Visual Studio, click `Start Debugging` (or tap F5).
  2. From the menu bar, navigate to Debug > Windows > Modules to open the Modules window.
  3. For each of the following modules, locate the module > right click > choose `Load Symbols`:
    1. RuntimeCoreNet.dll
    2. runtimecore.dll
  4. Ensure the `Symbol Status` for each module above is `Symbols loaded`.
  5. Run through the workflow that reproduces the problem.
  6. From the menu bar, navigate to Debug > Windows > Threads to open the Threads window.
  7. Locate and select the thread showing the current execution point (yellow arrow).
  8. If the current execution thread shows no references to ArcGIS Runtime locate the faulting thread.
  9. Inspect for references to ArcGIS Runtime.
  10. Select the thread of interest in the threads window.
  11. From the menu bar navigate to Debug > Windows > Call Stack to view the call stack for the thread.
  12. In the Call Stack window right click, choose Select All and copy the selected text.

 

For more information see How to use the threads window in the Visual Studio documentation.

 

Workflow 2. Debug a dump file

 

Create dump file from your application process

  1. Run through the workflow that reproduces the problem.
  2. When the application crashes open Windows Task Manager > select the `Details` tab > locate the process > Right click > choose 'Create dump file'.
  3. On the `Dumping Process` dialog that appears, take note of the file location (select the path text and copy).

 

Debug the Dump File

  1. In Visual Studio, navigate to File > Open > File.
  2. In the open file dialog, browse for and choose the <YourApplicationProcessName>.DMP file (or paste the path you copied earlier).
  3. On the Minidump File Summary page look for the collapsible Actions section.
  4. Choose `Debug with Mixed`.
  5. For each of the following modules, locate the module > right click > choose `Load Symbols`:
    1. Esri.ArcGISRuntime.dll
    2. RuntimeCoreNet.dll
    3. runtimecore.dll
  6. Ensure the `Symbol Status` for each module above is `Symbols loaded`.
  7. From the menu bar, navigate to Debug > Windows > Threads to open the Threads window.
  8. Locate and select the thread showing the current execution point (yellow arrow).
  9. If the current execution thread shows no references to ArcGIS Runtime locate the faulting thread.
  10. Inspect for references to ArcGIS Runtime.
  11. Select the thread of interest in the threads window.
  12. From the menu bar navigate to Debug > Windows > Call Stack to view the call stack for the thread.
  13. In the Call Stack window right click, choose Select All and copy the selected text.

 

For more information see How to use the threads window in the Visual Studio documentation.

 

If you have copied the text for an ArcGIS Runtime related call stack you can add this information to a Geonet post or provide it to an Esri analyst when you contact Support to report your issue.

 

Example

 

The following example shows the type of ArcGIS Runtime call stack you might have in the event of an crash and shows how you might read a call stack to decipher potential causes of the problem and perhaps find a temporary workaround.

 

In July 2019 an ArcGIS Runtime user reported on Geonet a crash with 100.5 when their code called the asynchronous method RouteTask.SolveRouteAsync(). They did the best thing you can do in this situation by attaching a simple standalone reproducer application to the Geonet post. It enabled the development team to repeat the exact workflow and get the call stack using the 100.5 symbol files. The call stack showed that ArcGIS Runtime code was failing within geometry spatial reference handling, which allowed us to recommend a straightforward workaround: specify the SpatialReference when creating MapPoint geometries to represent Stops. Now with 100.6, you too have access to the symbol files giving you a head start on identifying possible causes and temporary workarounds, and more specific information to share with us when reporting your issue. In this case, thanks to the excellent reproducer application from the user we were able to quickly diagnose and fix this bug for the 100.6 release.

 

Example call stack:

> runtimecore.dll!Esri_runtimecore::Geometry::Spatial_reference_impl::horizontal_equal_(class Esri_runtimecore::Geometry::Spatial_reference_impl const &) Unknown
runtimecore.dll!Esri_runtimecore::Geometry::Spatial_reference_impl::equals(class Esri_runtimecore::Geometry::Spatial_reference const &) Unknown
runtimecore.dll!Esri_runtimecore::Network_analyst::reproject(class std::shared_ptr<class Esri_runtimecore::Geometry::Geometry> const &,class std::shared_ptr<class Esri_runtimecore::Geometry::Spatial_reference> const &,class std::shared_ptr<class Esri_runtimecore::Geometry::Spatial_reference> const &) Unknown
runtimecore.dll!Esri_runtimecore::Network_analyst::NA_utils::reproject<class Esri_runtimecore::Network_analyst::Stop>(class std::shared_ptr<class Esri_runtimecore::Geometry::Spatial_reference> const &,class std::vector<class Esri_runtimecore::Network_analyst::Stop,class std::allocator<class Esri_runtimecore::Network_analyst::Stop> > &) Unknown
runtimecore.dll!Esri_runtimecore::Network_analyst::Local_route_task::initialize_stops_(class Esri_runtimecore::Network_analyst::Route_parameters const &,class std::vector<class Esri_runtimecore::Network_analyst::Stop,class std::allocator<class Esri_runtimecore::Network_analyst::Stop> > const &,class std::vector<class Esri_runtimecore::Network_analyst::Stop,class std::allocator<class Esri_runtimecore::Network_analyst::Stop> > &,class std::shared_ptr<class Esri_runtimecore::Geodatabase::Transportation_network_view> const &,class std::vector<struct Esri_runtimecore::Network_analyst::Solve_condition,class std::allocator<struct Esri_runtimecore::Network_analyst::Solve_condition> > &,class std::vector<struct Esri_runtimecore::Network_analyst::Solve_condition,class std::allocator<struct Esri_runtimecore::Network_analyst::Solve_condition> > &) Unknown
runtimecore.dll!Esri_runtimecore::Network_analyst::Local_route_task::solve(class Esri_runtimecore::Network_analyst::Route_parameters,class pplx::cancellation_token const &) Unknown
runtimecore.dll!Esri_runtimecore::Mapping::Local_solve_operation::solve_async(class std::shared_ptr<class Esri_runtimecore::Mapping::Request_delegator> const &,class std::shared_ptr<class Esri_runtimecore::Mapping::Route_parameters> const &,class Esri_runtimecore::Mapping::Task_completion_source<class std::shared_ptr<class Esri_runtimecore::Mapping::Route_result> >,class Esri_runtimecore::Mapping::Task_options) Unknown
runtimecore.dll!<lambda_892f625b129cc43ba2b282eeb1ecc18f>::operator()<pplx::task<boost::any>>() Unknown
runtimecore.dll!std::_Func_impl_no_alloc<<lambda_31388138151c3f34bc6c36ef59ef90df>,boost::any,pplx::task<boost::any>>::_Do_call() Unknown
runtimecore.dll!std::_Func_class<class boost::any,class pplx::task<class std::vector<class boost::any,class std::allocator<class boost::any> > > >::operator()(class pplx::task<class std::vector<class boost::any,class std::allocator<class boost::any> > >) Unknown
runtimecore.dll!pplx::details::_PPLTaskHandle<class boost::any,struct pplx::task<class boost::any>::_ContinuationTaskHandle<class boost::any,class boost::any,class std::function<class boost::any >,struct std::integral_constant<bool,1>,struct pplx::details::_TypeSelectorNoAsync>,struct pplx::details::_ContinuationTaskHandleBase>::invoke(void) Unknown
runtimecore.dll!pplx::details::_TaskProcHandle::_RunChoreBridge(void *) Unknown
runtimecore.dll!Esri_runtimecore::Common::Core_scheduler::bridge_proc_(void *) Unknown
runtimecore.dll!Esri_runtimecore::Common::Windows_Threadpool_scheduler::Scheduler_param::work_callback(struct _TP_CALLBACK_INSTANCE *,void *,struct _TP_WORK *) Unknown
ntdll.dll!77597dc4() Unknown
ntdll.dll![Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll] Unknown
[External Code]

The Runtime .NET team is excited to announce the release of ArcGIS Runtime SDK for .NET 100.6. This release includes significant new features, performance improvements, and bug fixes you can read about here… and for our .NET community we have some even more exciting news: this release includes a preview of our support for WPF for .NET Core 3.0.


WPF for .NET Core marks a significant step for the popular WPF UI framework for desktop apps by liberating it from the system-wide .NET Framework on which it currently depends and enabling you to:

  • Build a completely self-contained executable with your application and all dependencies
  • Update your target.NET version without imposing any system-wide .NET updates on your users
  • Benefit from future enhancements and performance improvements beyond .NET Framework 4.8

 

To try the Preview of Support for WPF for .NET Core:

 

Note:- To use the .NET Core SDK 3.0 Preview with Visual Studio 2019 you must be running 16.2 or later and enable the preview through Tools > Options > Preview Features.

 

Starting a new app

To try a new project from scratch using the .NET Core project templates, choose the `WPF App (.NET Core)` template from the new project dialog (tip: use the search or filters to narrow the list). In the Solution Explorer window for your new project instead of `References` you’ll now see `Dependencies` > `Frameworks` under which .NET Core is listed and if you open the project properties dialog you’ll see the Target framework is `.NET Core 3.0`. To add a reference to ArcGIS Runtime, right click Dependencies and choose `Manage NuGet Packages...` then browse for `Esri.ArcGISRuntime.WPF` from NuGet.org (or your local Esri package source) and install version 100.6.

 

Upgrading an existing app

To try upgrading one of your existing apps we recommend following this Microsoft docs article How to: Port a WPF desktop app to .NET Core which provides detailed instructions on porting your WPF desktop apps.

 

To see an example of a WPF desktop app ported to .NET Core 3.0 see this PR for our public samples.

 

Note:- The Preview of ArcGIS Runtime SDK for .NET with support for WPF for .NET Core 3.0 cannot be used in production (which differs from the status of .NET Core 3.0 Preview 8). When building, you’ll see a friendly reminder in your Error List “.NET Core support for ArcGIS Runtime is in Preview and not fully supported”.

 

When will the preview become available for use in production? That depends on the progress of .NET Core SDK v3.0 and v3.1 over the next few months but we hope it could be as soon as Q4 2019 or Q1-Q2 2020.


We’re truly excited about the direction WPF is taking with the support for.NET Core and hope one day it may even allow us to deprecate support for .NET Framework…

 

We look forward to any feedback you have on your experience using this preview.

 

Thanks

 

The Runtime .NET Team

Data is at the heart of every business. Collecting and storing data is done in a variety of ways, from paper forms to custom-built applications. You, our customers, have asked us to help with the transition from paper to digital by providing you with a collection app that is configurable and customizable to work with your own data and specific workflows.

 

We are proud to deliver an open source app that hopefully fits many of your organization's data collection needs. Because we are releasing the app open source and under an Apache license, you are welcome to take it, modify it to match your needs, and use it as you see fit.

 

Data Collection for .NET is a WPF application built using the ArcGIS Runtime SDK for .NET and it features common functionality encountered when collecting data.

 

Identify map data

 

Identify

 

Collecting data means also knowing what is around you. Click on one of the data points on the map to bring up information about it. If you need to edit it, clicking on the pencil icon will start an edit session. It's as simple as that!

 

Collect new data point

 

Collect

 

When you're ready to add a new data point, click the plus button to begin. You'll be prompted to select a location for your new data point and add some information about it.

 

Work offline

 

Offline

 

To support remote collection in areas without network access, we added the ability to work offline. Simply navigate the map to your desired work area and select "Work Offline" from the menu. The app will download the map along with its data and will allow you to collect data points when you are disconnected from the network. When you're back in the office or able to connect to a network, select "Sync Map" from the menu to have your changes merged with the online version of your map.

 

Do you think this is something you could use? Take a look at the full documentation and get the source code to the app from GitHub!

 

Happy collecting!

We are excited to announce the release of the Toolkit for ArcGIS Runtime SDK for .NET v100.4. The Toolkit contains controls and utilities you can use out-of-the-box to accelerate the development of your .NET apps for Android, iOS, and Windows. You also have access to the complete Toolkit source code on Github enabling you to fully customize the Toolkit for your specific project requirements.

 

Features

  • Legend: Display a legend for a single layer in your map or scene and optionally for its sub layers.
  • SymbolDisplay: Render a symbol in a control (also used in the Legend).
  • PopupViewer: Display details and media, edit attributes, geometry and related records, and manage the attachments of features and graphics (popups are defined in the popup property of features and graphics).
  • Compass: Automatically show a compass when the user rotates map. Optionally auto-hide the compass when the user rotates the map north up.
  • FeatureDataField: Display and optionally allow editing of a single field attribute of a feature.
  • MeasureToolbar: Measure distances and areas on the map view.
  • ScaleLine: Display the current scale of the map view.
  • TimeSlider: Allow the interactive definition of a time extent and animate time moving forward or backward. Can be used to manipulate the time extent in a map or scene view.

Where possible each control is available for all APIs supported for development with ArcGIS Runtime SDK for .NET: UWP, WPF, Xamarin.Android, Xamarin.iOS, and Xamarin.Forms for Android, iOS, and UWP. Feature availability by platform/API is indicated in the Github repo readme.

 

Getting started

As a developer you have three options for working with the Toolkit:

  1. Reference the latest stable or pre-release package from NuGet.org
  2. Reference the latest master branch commit NuGet package from AppVeyor
  3. Build the Toolkit source

A set of basic samples are included in the Toolkit repo.

 

Roadmap

The Toolkit is an active development project with more controls and utilities on the roadmap. You can even get an early glimpse of some of these new controls in the Toolkit Preview package (currently in preview are the SignInForm and TableOfContents for WPF). Also on the roadmap are improved Guide and API reference documentation and additional samples.

 

Reporting issues

We encourage you to try out and use the Toolkit within your projects and we look forward to hearing your feedback. If you find any bugs while using the Toolkit please submit new issues in the Toolkit repo. At this time we are not accepting new PRs for full features but if there are new controls you would like to see included please submit an issue to request the enhancement.  

 

Cheers

 

The ArcGIS Runtime .NET Team

Beta 3 of the Toolkit for ArcGIS Runtime SDK for .NET is now available on NuGet.org. The latest beta has been updated to reference the v100.2.1 release of ArcGIS Runtime SDK for .NET and includes the following new features and enhancements:

  • Compass for Xamarin.Android, Xamarin.iOS, and Xamarin.Forms (Android, iOS, and UWP)
  • Legend, LayerLegend, and SymbolDisplay for Xamarin.Android, Xamarin.iOS, and Xamarin.Forms (Android, iOS, and UWP)
  • ScaleLine for Xamarin.Android, Xamarin.iOS, and Xamarin.Forms (Android, iOS, and UWP)
  • TimeSlider for UWP, WPF, and Xamarin.iOS
  • MeasureToolbar for UWP, and WPF
  • Enhanced Toolbox support for Visual Studio
  • Sample apps for Xamarin.Android, Xamarin.iOS, and Xamarin.Forms (Android, iOS, and UWP)
  • API review
  • Numerous bug fixes!
  • Coming soon: TimeSlider for Xamarin.Android and Xamarin.Forms

 

See the repo readme for the full list of feature availability by API platform.

 

The previous beta was delivered as multiple platform-specific NuGet packages (at the time just UWP and WPF). The project has been reorganized to consolidate those into the Esri.ArcGISRuntime.Toolkit package for UWP, WPF, Xamarin.Android, and Xamarin.iOS development and a Esri.ArcGISRuntime.Toolkit.Xamarin.Forms package. Use the NuGet Package Manager UI, Console, or CLI tools to update your projects. You can always get the latest build of the Master branch anytime by adding a new NuGet Package Source referencing the CI server.

 

Please submit an issue if you find a bug!

 

 

Cheers

 

The ArcGIS Runtime .NET Team

The good newsFeatures and graphics in your ArcGIS Runtime SDK for .NET app can be labeled using a combination of attribute values, text strings, and values calculated with an expression. You can set font characteristics, determine how labels are positioned and prioritized, and how conflicts between overlapping labels are automatically and dynamically resolved. By creating one or more label classes, you can define distinct labels for groups of features.

The bad news: As of the 100.2.1 release, there's no API exposed for this. To implement labeling for a feature layer, graphics overlay, or map image sub-layer, you need to craft the appropriate JSON definition (text) to define your label classes (as described here). Bummer.

 

But don't worry, a simple JSON serializable class is all it takes to simplify your labeling code. I'll walk you through the basic process in the steps below. If that's still too much work for you, feel free to simply download the attached code and try it out. The labeling class in the project (LabelClassInfo.cs) can be brought into any ArcGIS Runtime for .NET project and used to create labels for your layers.

 

  1. Start Visual Studio and create a new ArcGIS Runtime SDK for .NET app. 
  2. Add a new class to the project. Let's name it LabelClassInfo.cs. Add the following using statements at the top of the class.
    using Esri.ArcGISRuntime.Geometry;
    using Esri.ArcGISRuntime.Symbology;
    using System;
    using System.IO;
    using System.Runtime.Serialization;
    using System.Runtime.Serialization.Json;

     

  3. Decorate the class with the DataContract attribute. This indicates that the class will be serializable. 
        [DataContract]
        public class LabelClassInfo
        {

     

  4. Create properties for everything expected in the JSON definition of the label class. This information is defined under labelingInfo in the Web map specification. The specification defines an "allowOverrun" value, for example. This could be implemented with the following simple bool property. Note that the name of the property in the class does not need to match the name in the specification.
            public bool AllowOverrun { get; set; }
    Based on the specification, here are the properties (and corresponding data type) needed for the label class: allowOverrun (bool), deconflictionStrategy (string), labelExpression (string), labelExpressionInfo (object), labelPlacement (string), minScale (int), maxScale (int), name (string), priority (int), removeDuplicates (string), removeDuplicatesDistance (int), repeatLabel (bool), repeatLabelDistance (int), stackLabel (bool), stackAlignment (string), symbol (TextSymbol), useCodedValues (bool), where (string).
  5. OK, the list above looks pretty straightforward, except for the two properties that don't return primitive data types. Go ahead and create properties for everything except labelExpressionInfo and symbol (we'll circle back to those). 
  6. After you've defined the properties, in order to make them serializable you'll need to decorate them with the DataMember attribute. The string you supply for "Name" will be used in the output JSON and must match the name used in the Web map specification. Add the appropriate DataMember attribute to all properties.
            [DataMember(Name = "deconflictionStrategy")]
            public LabelPosition LabelPosition { get; set; }

     

  7. The labelExpressionInfo property, returns object. What kind of object do we need here? In the specification, the JSON describes a class with a single property (not counting the deprecated "value" property). You'll therefore need to create a new private class (nested under your main class) with a single property that holds a (string) expression. This class will also be serializable, so you need the DataContract and DataMember attributes. 
            [DataContract]
            private class ExpressionInfo
            {
                [DataMember(Name = "expression")]
                public string Expression { get; set; }

                public ExpressionInfo(string expression)
                {
                    Expression = expression;
                }
            }

     

  8. The labelExpressionInfo property should be based on the new ExpressionInfo type. To simplify the API, you might want to expose just the expression property (ArcadeExpression in the example below) and build the ExpressionInfo object that contains it internally. 
            [DataMember(Name ="labelExpressionInfo")]
            private ExpressionInfo _labelExpressionInfo = new ExpressionInfo("");

            public string ArcadeExpression
            {
                get { return _labelExpressionInfo.Expression; }
                set { _labelExpressionInfo = new ExpressionInfo(value); }
            }

     

  9. What about the symbol property that returns TextSymbol? You can handle this is much the same way: expose a public Symbol property of type TextSymbol, then use an internal property to get its JSON representation (yes, Esri.ArcGISRuntime.Symbology.Symbol is serializable!).
            public TextSymbol Symbol { get; set; }

            [DataMember(Name = "symbol")]
            private string SymbolString
            {
                get { return this.Symbol.ToJson(); }
                set { this.Symbol = (TextSymbol)TextSymbol.FromJson(value); }
            }

     

  10. Finally, create a method on LabelClassInfo to return the JSON representation of the object.
            public string GetJson()
            {
                // Create a JSON serializer for the label class.
                DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(LabelClassInfo));

                // Write the object to a memory stream.
                MemoryStream stream = new MemoryStream();
                jsonSerializer.WriteObject(stream, this);

                // Read the stream to a string.
                stream.Position = 0;
                StreamReader reader = new StreamReader(stream);
                string json = reader.ReadToEnd();

                // HACK: clean up the json a bit.
                json = json.Replace("\"{", "{").Replace("}\"", "}").Replace("\\", "\"").Replace("\"\"", "\"");

                // Return the serialized string.
                return json;
            }

     

  11. You should now be able to use the new LabelClassInfo class to write code like the following to apply labels to a feature layer!
                TextSymbol textSymbol = new TextSymbol
                {
                    FontFamily = "Arial",
                    FontWeight = weight,
                    Size = (int)TextSizeComboBox.SelectedValue,
                    HorizontalAlignment = Esri.ArcGISRuntime.Symbology.HorizontalAlignment.Left,
                    VerticalAlignment = Esri.ArcGISRuntime.Symbology.VerticalAlignment.Bottom,
                    Color = (Color)ColorComboBox.SelectedValue
                };

                // Create a new LabelInfo object and set the relevant properties (including the text symbol).
                LabelClassInfo labelInfo = new LabelClassInfo()
                {
                    LabelPosition = "static",
                    ArcadeExpression = "return $feature['" + LabelFieldComboBox.SelectedItem + "'];",
                    MinScale = 0,
                    MaxScale = 0,
                    Priority = 30,
                    RemoveDuplicateLabels = "featureType",
                    StackLabel = true,
                    Symbol = textSymbol
                };

                // Get the raw JSON from the label info object.
                labelJson = labelInfo.GetJson();

                // Create a new label definition from the JSON string.
                LabelDefinition labelDef = LabelDefinition.FromJson(labelJson);

                // Clear existing label definitions.
                _parcelsLayer.LabelDefinitions.Clear();

                // Add the new label definition.
                _parcelsLayer.LabelDefinitions.Add(labelDef);

     

 

OK, so it might not be the easiest thing to code, but once you have it you can reuse this class anytime you need to add labels for a layer.

Apologies if the steps above were too vague or if you got stuck because I left something out! I've attached a project with the LabelClassInfo class and a WPF app for testing. The attached example also includes some enums for defining label position, placement, and handling of stacking and duplicates.

 

Update (2018 March 13):

  • I've attached a much cleaner version of the LabelClassInfo class ("LabelClassInfo2.cs") that uses Newtonsoft.Json (thanks to Matvei Stefarov on the ArcGIS Runtime SDK for .NET team).
  • Including a link to a a utility that helps create your serializable class from JSON: Instantly parse JSON in any language | quicktype 

If you've ever had to show the density of point features on a map, you may already be familiar with the concept of a heat map, which allows you to generalize the display of points according to their density. A heat map provides an excellent tool for discovering patterns in your data. In addition to looking at density of point location, you can also provide a field in your dataset with which to weight the density. This allows you to look at the density of things like sales (dollars, for example) instead of just the density of customers over an area.

 

Heat maps are displayed with a color ramp that usually shows dense areas with a darker color (red, for example) and sparse areas with a light color (such as yellow). You may have used a heat map renderer to display your point data in the ArcGIS Online map viewer or ArcGIS Pro. The heat map below shows the density of earthquakes weighted with a field that contains the magnitude.

Unique value points to heat map renderer

"Sounds great". You might be saying. "I'm excited to try it in my ArcGIS Runtime for .NET app"!
"Um, yeah. About that." I would say, sheepishly looking at my shoes.

 

While there is support in ArcGIS Runtime for reading things like a heat map renderer from a web map, there's no API exposed (as of v100.2.1) that allows you to construct one and apply it to a point layer without crafting the raw JSON definition. Fortunately, with a little effort, there's a way to make it much easier to work with.

 

In a previous blog, I described how to create a serializable class to define labeling properties to apply to a layer. I'll describe the same technique here to define a heat map renderer class that can be serialized to JSON and applied to your point layer. If you don't really care about the details and just want to start using it, you can download the completed class and sample project and give it a try.

 

  1. Start Visual Studio and create a new ArcGIS Runtime SDK for .NET app. 
  2. Use the NuGet Package Manager to add the Newtonsoft.Json package to the project.
  3. Add a new class to the project. Let's name it HeatMapRenderer.cs. Add the following using statements at the top of the class.
    using Newtonsoft.Json;
    using System;
    using System.Collections.Generic;
    using System.Windows.Media;
  4. Create properties for everything expected in the JSON definition of the heat map renderer class. This information is defined under heatmapRenderer in the Web map specification. The specification defines a "blurRadius" value, for example. This could be implemented with the following simple long property. Note that the name of the property in the class does not need to match the name in the specification. 
    public long BlurRadius { get; set; }
    Based on the specification, here are the properties (and corresponding data type) needed for the heat map renderer class:
    • blurRadius (long)
    • colorStops (list of objects)
    • field (string)
    • maxPixelIntensity (double)
    • minPixelIntensity (double)
    • type (string).
  5. OK, the list above looks pretty straightforward, except for the property that returns a list of objects. Go ahead and create properties for everything except colorStops (we'll circle back to that one). 
  6. The Type property needs to be set with "heatmap" as the default, as shown here.
    public string Type { get; set; } = "heatmap";
  7. After you've defined the properties, in order to make them serializable you'll need to decorate them with the  JsonProperty attribute. The string you supply will be used in the output JSON and must match the name used in the Web map specification. Add the appropriate JsonProperty attribute to all properties, as shown below for the BlurRadius property.
    [JsonProperty("blurRadius")]
    public long BlurRadius { get; set; }
  8. The colorStops value is defined with a list of objects. What kind of object do we need here? In the specification, the JSON describes a colorStop class with two properties: color and ratio. You'll therefore need to create a new class with those properties. Let's call the class ColorStop.
    public partial class ColorStop
    {
        [JsonProperty("ratio")]
        public double Ratio { get; set; }

        [JsonProperty("color")]
        public int[] Color { get; set; }
    }
  9. The ratio property is a double. Color is a four value array (R, G, B, A). The constructor for ColorStop will accept a ratio (double) and a Color. The color values are used to set the array.
    public ColorStop(double ratio, Color color)
    {
        Ratio = ratio;
        Color = new int[] { color.R, color.G, color.B, color.A };
    }
  10. Return to the HeatMapRenderer class and add a property to hold the color stops. Initialize the property with an empty list of color stops.
    [JsonProperty("colorStops")]
    public List<ColorStop> ColorStops { get; set; } = new List<ColorStop>();
  11. Add some helper methods to add or clear color stops in the collection.
    public void AddColorStop(double ratio, Color color)
    {
        if (ratio > 1.0 || ratio < 0.0) { throw new Exception("Argument 'ratio' must be a value between 0 and 1."); };

        ColorStop stop = new ColorStop(ratio, color);
        ColorStops.Add(stop);
    }

    public void ClearColorStops()
    {
        ColorStops.Clear();
    }
  12. Finally, add a ToJson method that returns the JSON representation of the class.
    public string ToJson()
    {
        return JsonConvert.SerializeObject(this);
    }
  13. You should now be able to use the new HeatMapRenderer class to write code like the following to apply a heat map renderer to a point feature layer!
    // Create a new HeatMapRenderer with info provided by the user.
    HeatMapRenderer heatMapRendererInfo = new HeatMapRenderer
    {
        BlurRadius = blurRadius,
        MinPixelIntensity = minIntensity,
        MaxPixelIntensity = maxIntensity
    };

    // Use a selected field to weight the point density if the user chooses to do so.
    if (UseFieldCheckBox.IsChecked == true)
    {
        heatMapRendererInfo.Field = (FieldComboBox.SelectedValue as Field).Name;
    } 

    // Add the chosen color stops (plus transparent for empty areas).
    heatMapRendererInfo.AddColorStop(0.0, Colors.Transparent);
    heatMapRendererInfo.AddColorStop(0.10, (Color)StartColorComboBox.SelectedValue);
    heatMapRendererInfo.AddColorStop(1.0, (Color)EndColorComboBox.SelectedValue);

    // Get the JSON representation of the renderer class.
    string heatMapJson = heatMapRendererInfo.ToJson();

    // Use the static Renderer.FromJson method to create a new renderer from the JSON string.
    var heatMapRenderer = Renderer.FromJson(heatMapJson);

    // Apply the renderer to a point layer in the map.
    _quakesLayer.Renderer = heatMapRenderer;

I'd agree with you if you think this is a lot of code to write to implement a heat map renderer. But remember, this class can be used in all your ArcGIS Runtime for .NET apps when you want to apply heat map rendering.

 

Apologies if you were unable to successfully follow the steps above. Fortunately, the attached project contains the HeatMapRenderer class, as well as a WPF app for testing the heat map renderer.

We like to think that the world is mostly digital and that all field personnel hop from job site to job site armed with tablets that are auto-magically kept in sync for them by highly sophisticated software and nobody uses paper maps anymore. While that is certainly true for some, the reality is that paper maps are a long way from being replaced. So why, with all the global efforts going on to eliminate paper, are paper maps so hard to replace?

 

One of the most common reasons is a budgetary constraint. Companies cannot afford to invest in tablets, training, and mapping software for each field worker. Publishing a web map that the field worker could access on their laptop is a solution to the budgetary constraint, but that introduces the issue of not being able to access the maps in a disconnected environment. Another cause is that some of the existing apps are just too complicated. So paper maps do the job because they are simple, inexpensive, and available anywhere.

 

How Offline Mapbook competes with paper maps

We have engineered the Offline Mapbook example application to be a very simple, easy to use map viewing app. It works on any Windows device running Windows 7 and above and is designed to work fully offline. The interface is simple, intuitive and touch friendly. It's free and open sourced so it can be modified to fit anyone's needs.

 

One mapbook, multiple maps

Using a mobile map package makes it easy to have multiple maps in one app.

 

Maps Screen

 

Table of Contents and Legend

Maps with multiple superimposed data layers are hard to discern. The Table of Contents in the Offline Mapbook lets users turn layers on and off as needed.

 

Table Of Contents

 

Locate

Multiple locators can be configured within the mobile map package to facilitate searching for both map features and addresses. 

 

Locate

 

Identify

More information about a feature is available by clicking or tapping on it. 

Identify

 

Offline capabilities and syncing

While the app is designed to function in a fully disconnected environment, that does not mean the data becomes stale once loaded. Every time the app is started, if an internet connection is present, it checks the location of the mobile map package to see if a new one is available to download. 

 

 

Get more info

Often times we try to do everything at once. We try to make an app that visualizes and collects and analyzes, but we lack the budget or the skill set. More often than not, the intended audience is overwhelmed by the amount of features they are presented with, and the uptake is slow and painful. This app was designed with all that in mind, to give you a simple way to get digital data into people's hands now, and let you worry about collecting and analyzing later. 

 

Click here to read more about the app.

We're hard at work getting an updated toolkit for the new Runtime SDK out.

 

Even though we have some ways to go, we wanted to share the progress with you all, and provide you with an opportunity to try things out, give us feedback, or simply just use what's there.

 

We have an active branch going on Github that you can download and use today.All the source code is there, and is really easy to build and use:

 

https://github.com/Esri/arcgis-toolkit-dotnet/tree/v100

 

This includes a set of controls for WPF and UWP:

  • ChallengeHandler - (WPF only) Displays a UI dialog to enter or select credentials to use when accessing secure ArcGIS resources, as well as helper classes for storing credentials in Windows' credentials cache.
    • Compass - Shows a compass direction when the map is rotated. Auto-hides when the map points north up.
    • Legend - Displays a legend for a single layer in your map (and optionally for its sub layers).
    • ScaleLine - Displays current scale reference.
    • SymbolDisplay - Renders a symbol in a control.
    • TableOfContents (WPF)- Creates a tree-view of the entire map document. Optionally displays legend information for the layers as well.

     

    Please be aware that we might significantly refactor these controls, add more controls and helpers (or even remove some), so expect changes when you pull updated code from time to time. You can keep an eye on this Pull Request and monitor changes we're making.

     

    There's also a test app. It's not the prettiest (yet), and is mostly used to test the controls so far, but should help you get started. Further down the line we'll provide a proper sample app with documentation and various examples showcasing the use of these controls.

     

    What about Xamarin? It's on our roadmap, but we're first focusing on WPF, which in turn means we get UWP support almost for free.

     

    Feel free to comment below here to provide feedback etc.

    The ArcGIS Runtime .NET team is proud to announce that the Quartz betas of the ArcGIS Runtime SDKs for .NET and Xamarin are now available.

     

    The beta contains exciting new functionality not previously available in the 10.2.X releases, including: mobile map packages, vector tiled layers, and raster layers, plus full support for Windows 10 Universal Windows Platform (UWP) apps. Did I forget to say your awesome GIS C# code will also now run on Windows, AND Android, AND iOS?! Beta releases don't get more exciting than this!! Learn all about the Betas in the .NET release notes, Xamarin release notes and blog post. Download the Beta software from the Early Adopter Community site by signing in with your ArcGIS Online account or create a new beta account.

     

    We appreciate you taking the time to test our beta and look forward to hearing your feedback in the Early Adopter Community forum.

     

    Cheers

     

    The .NET team

    Lots of fixes and performance improvements, but most importantly: Support for 3D and KML!

     

    Full details here: ArcGIS Runtime SDK 10.2.6 for .NET is now available! | ArcGIS Blog

     

    desktop.PNG

    KmlViewer.png

    WinPhone_Scene.PNG

    We have uploaded demos that were shown in Developer Summit 2015 sessions to ArcGIS Online as a code samples.

     

    Please follow links below to the items for download.

     

     

    Also see related post about session recordings

    .NET Runtime - DevSummit 2015 Sessions

    The 2015 devsummit session recordings have started coming online.

     

    Below is a list of .NET Runtime related session recordings - More to come (I'll update the list as they do)

     

    .NET Specific sessions:

    Getting Started with the ArcGIS Runtime SDK for .NET | Esri Video

    The first steps to using the runtime in a .NET-based app and an overview

     

    ArcGIS Runtime SDK for .NET: Using MVVM | Esri Video

    Goes through rewriting an app to use good MVVM patterns

     

    ArcGIS Runtime SDK for .NET: Tips and Tricks | Esri Video

    The .NET Team's Top 10 tips - Lots of little good tidbits for you

     

    Preview of ArcGIS Runtime and Xamarin | Esri Video

    Get a sneak peak of the runtime for Xamarin

     

    Runtime sessions that apply to all the supported platforms

    Getting Started with the ArcGIS Runtime | Esri Video

    Intro about the runtimes in general

     

    ArcGIS Runtime SDKs: Building Offline Apps, Part I | Esri Video

    ArcGIS Runtime SDKs: Building Offline Apps, Part II | Esri Video

    Two-part series on going offline with the runtime

     

    ArcGIS Runtime SDKs: Core Display Architecture Performance Tips and Tricks | Esri Video

    Great low-level look at how the Runtime Rendering engine works and how you can optimize your rendering with this knowledge

    When using the MVVM style pattern to build your XAML-based app, you don't want to include references to your View objects from within your ViewModel. This means that the ViewModel won't be able to for instance call "Zoom" on the MapView, because this operation is on the MapView, and the ViewModel is not allowed to have a reference to anything on the View. You'll find similar common challenge with ScrollViewer, where you want to scroll to a certain item in a list, but again the scroll operation is on the view, since this is a view operation.

     

    The pattern to handle this is to create a controller your ViewModel owns, and you bind this to the view object, using an attached property. The ViewModel can then 'request' zoom operations on the controller, and if that controller is bound to a map view, it will handle executing the SetView call on the MapView.

     

    I've added an example of this to the WPF Desktop Sample App:

    arcgis-runtime-samples-dotnet/NavigateFromViewModel.xaml.cs at master · Esri/arcgis-runtime-samples-dotnet · GitHub

    arcgis-runtime-samples-dotnet/NavigateFromViewModel.xaml at master · Esri/arcgis-runtime-samples-dotnet · GitHub

     

    The attached property is shown here on line 1:

     

    <esri:MapView local:MapViewController.Controller="{Binding Controller}">
         <esri:Map>
              <esri:ArcGISTiledMapServiceLayer
                    ServiceUri="http://services.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer" />
         </esri:Map>
    </esri:MapView>
    

     

    The ViewModel class defines an instance of MapViewController, and exposes it in the property "Controller", which is what is being bound above.

     

    Inside the controller, code is triggered when it is bound to the MapView and will keep an internal weak reference* to the map view, so that it can perform the operation if it is bound. The Controller can also expose properties from the MapView back out, like in this example where the current 'Extent' property is available for use to add bookmarks. You could add more properties like the current Scale or Rotation, or add more commands to perform on the view.

     

    Using this pattern, the ViewModel never knows anything about the MapView, but is still able to perform zoom operations.

     

    This pattern works just as well with Windows Store and Windows Phone as well, and you can copy the MapViewController class over to use the as well.

     

    *We're using weak references to the MapView and it's events. It complicates the sample a little, but it ensure that if the ViewModel stays around for a long time, but you close the page/window that the MapView is on, the MapView control won't stay around in memory, but can be garbage collected.