Getting ready for the new ArcGIS Runtime SDK for the Microsoft .NET Framework

Last summer we announced in this blog post we were working on a new SDK called ArcGIS Runtime SDK for the Microsoft .NET Framework. This SDK would take all our experience building APIs and SDKs for the Windows desktop, Windows Phone and Windows Store app platforms, and bring them together in one SDK. Since the announcement, we know many of you have been thinking about code and skills you have developed with the existing ArcGIS Runtime SDK for WPF and asking how you can best plan for a transition to the Windows Desktop API included with the new .NET SDK. This blog post will help you prepare for the arrival of the new SDK by providing tips you can follow today in the current WPF SDK.

The first question you might ask is, what about all the great skills and knowledge I have built up working with the existing WPF SDK? The good news is, they are still very relevant for the new .NET SDK. You can consider the new Windows Desktop API an evolution of the existing WPF API, sharing many of the concepts and even many of the actual class and class member names. However it is based on a more recent version of the .NET Framework, takes advantage of modern patterns and practices such as MVVM and async Tasks and is built with the benefit of several years experience creating .NET APIs for developers. This means you will find some differences between the APIs.

The second question you should rightly ask is, do I need to port all my existing WPF apps to the new API? And the answer might be no. With the knowledge migration will involve some development effort you should consider each app individually, assessing whether you require any functionality which is only available in the new API. Those apps which would not benefit from the new API can continue to build from the existing WPF API. We will continue to support the existing WPF SDK with future releases focussed on quality, performance and compatibility with the ArcGIS system.

If there are features you require from the new API you will need to plan to migrate those apps to the new API. Here are three recommendations you can implement today using the 10.2 release of the WPF SDK which will make your code easier to transition to the new .NET SDK:

1. Use the accelerated display mode

What is the accelerated display?

In the existing WPF SDK you can choose to have all of your map, or a specific subset of layers, rendered with the GIS-optimized map rendering engine termed the ‘accelerated display’. The accelerated display is particularly beneficial when you would like to display many thousands of graphics (or features) although it can also render other operational layers and your basemaps layers too. This display is in fact the same map rendering engine used by all the other ArcGIS Runtime SDKs. In the forthcoming .NET SDK, the Map has been re-engineered and now also only uses the high performance rendering mode for your entire map.

How do I enable the accelerated display?

To have your entire map rendered in the accelerated display mode you should use the Map.UseAcceleratedDisplay property. This is the recommended approach. Alternatively, it is possible for a specific subset of layers to be rendered with the accelerated display. To enable this behavior you use the AcceleratedDisplayLayers group layer. Any layers within this group layer will be rendered by the accelerated display but note you may only add a single instance of an AcceleratedDisplayLayers group layer to your Map.

For example the following map uses the standard WPF rendering:

<esri:Map x:Name="MyMap" WrapAround="True">
    <esri:ArcGISTiledMapServiceLayer ID="MyLayer" 
       Url="http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer"/>
    <esri:GraphicsLayer ID="MyGraphics" Renderer="{StaticResource MySimpleRenderer}"/>
</esri:Map>

The following map is entirely rendered using the ArcGIS Runtime map by simply setting the UseAcceleratedDisplay property to True:

<esri:Map x:Name="MyMap" UseAcceleratedDisplay="True" WrapAround="True">
    <esri:ArcGISTiledMapServiceLayer ID="MyLayer" 
       Url="http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer"/>
    <esri:GraphicsLayer ID="MyGraphics" Renderer="{StaticResource MySimpleRenderer}"/>
</esri:Map>

Why is the accelerated display mode not the default rendering mode in the WPF SDK?

The accelerated display is not the default rendering mode in the WPF SDK because the WPF API was already available as a standalone product before we began adding ArcGIS Runtime components to the API and released it as the ArcGIS Runtime SDK for WPF. There were inevitably some aspects of the preexisting API that could not be immediately supported in the accelerated display mode. In order to avoid making such a significant breaking change we retained both rendering pipelines and made the accelerated mode an opt-in experience.

What aspects of the existing WPF SDK are not supported in the accelerated display mode?

The biggest difference you will likely encounter is in the support for custom XAML symbols. To achieve maximum performance, the accelerated display mode in the WPF SDK only supports the standard esri symbol and renderer types (SimpleMarkerSymbol, SimpleRenderer, etc). Because the new .NET SDK only uses the optimized map rendering pipeline of the ArcGIS Runtime it does not support custom XAML symbols. There are some other layer types and renderer types not supported in the accelerated display in the WPF SDK (see the Release Notes) but in most cases these have since been implemented in the new .NET SDK (for example the TemporalRenderer). Additionally the new SDK includes a CompositeSymbol type which allows you to create a custom symbol from combinations of the standard esri types.

2. Use the async Task support in 10.2 WPF SDK

What are async Tasks?

Writing high performance, responsive applications requires you to use an asynchronous pattern where time consuming operations or operations you would like to run concurrently are executed on separate threads. Managing multiple threads, however, can be very complicated. Microsoft introduced Tasks in .NET 4.0 as a model for simplifying the process of writing multi-threaded applications. You can use .NET Tasks to asynchronously execute code without needing to worry about the actual threads performing the work. Tasks also provide much greater control over their execution and over what happens when they have completed, making it much simpler to: wait for a Task to complete; specify the order in which a number of Tasks should execute; or wait for several Tasks to all complete before executing a specific piece of code. Version 5 of the C# language further simplified working with Tasks with the addition of the ‘async’ and ‘await’ keywords. For more information about async Tasks please see Asynchronous Programming with Async and Await.

Where are these Tasks in the WPF API?

One the most exciting new features in the ArcGIS Runtime SDK 10.2 for WPF was undoubtedly the ability for any asynchronous methods to return a Task instance to represent the execution of an operation. Prior to 10.2, the API provided both an asynchronous method as well as a synchronous method for any potentially time-consuming operation. At 10.2, these operations have an additional method denoted by the suffix ‘…TaskAsync’. For example the QueryTask class has the synchronous method ‘Execute’, the traditional asynchronous method ‘ExecuteAsync’ and the new Task-based method ‘ExecuteTaskAsync’.

How can I use the new Task-based async methods?

It is possible to work with Tasks in .NET 4.0 without any additional software. However, to realize the full benefit of the new Task pattern and use the ‘async’ and ‘await’ keywords you must either be using .NET 4.5 and Visual Studio 2012 (or above) or alternatively if you need to stay on .NET 4.0 you can access this functionality with the Microsoft Async NuGet package.

Once you are ready to embrace Tasks you will need to make some changes to your code. These changes involve removing the declaration of delegates (i.e. named event handlers, inline anonymous methods or lambda expressions) and replacing them with an await call to the new Task-based method. The call to the async method must be wrapped in a try/catch statement because Tasks throw exceptions rather than raising a ‘Failed’ event. Your code which previously executed when the async method completed successfully can be placed after the method call and your code which ran in the event of a failure should be placed in the catch clause. These changes have two immediate benefits which are to reduce the number of lines of code and make your code more readable.

Consider the two examples below, the first executes a QueryTask operation using the traditional event-based approach whilst the second example uses the new 10.2 Task-based functionality.

The first example uses the existing event-based pattern with inline lambda expressions to handle the ExecuteCompleted and the TaskFailed events. This approach is more long winded and the logic does not progress linearly making the code more difficult to read. When using lambda expressions it is important to remember that you are registering event handlers and therefore that in some situations you may need to unregister these handlers in order to avoid them being called multiple times, which complicates the declaration of the delegates and starts to negate some of the convenience.

QueryTask queryTask = new QueryTask
    ("http://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer/3");

// Use in-line Lambda expression to handle the ExecuteCompleted event.
queryTask.ExecuteCompleted += (obj, queryEventArgs) =>
{
    // Do something with results...
    GraphicsLayer graphicsLayer = MyMap.Layers["MyGraphics"] as GraphicsLayer;
    graphicsLayer.Graphics.AddRange(queryEventArgs.FeatureSet.Features);
};

// Use in-line Lambda expression to handle the Task Failed event.
queryTask.Failed += (obj, taskFailedeventArgs) =>
{
    if (taskFailedeventArgs.Error != null)
        MessageBox.Show(taskFailedeventArgs.Error.Message);
};

// Call ExecuteAsync after in-line event handler declaration.
queryTask.ExecuteAsync(new Query()
{
    Where = "1=1",
    ReturnGeometry = true,
    OutSpatialReference = MyMap.SpatialReference
});

This second example uses the new QueryTask.ExecuteTaskAsync method which returns an ‘awaitable’ Task. The Result property of the Task contains a QueryResult instance, indicated by the Task<QueryResult> return type. Using the ‘await’ keyword allows you to make the asynchronous method call and pause the code and for control to be returned to the user until the method completes and the code execution can continue. One nice aspect of this approach is the code appears to execute linearly, greatly enhancing the readability of your code. Remember, Tasks throw exceptions if a problem is encountered as opposed to raising ‘failed’ style events and therefore it is important to make appropriate use of the try/catch statement.

QueryTask queryTask = new QueryTask
    ("http://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer/3");

try
{
    // Call ExecuteTaskAsync using the await keyword
    QueryResult queryResult = await queryTask.ExecuteTaskAsync(new Query()
    {
        Where = "1=1",
        ReturnGeometry = true,
        OutSpatialReference = MyMap.SpatialReference
    });

    // Do something with results...
    GraphicsLayer graphicsLayer = MyMap.Layers["MyGraphics"] as GraphicsLayer;
    graphicsLayer.Graphics.AddRange(queryResult.FeatureSet.Features);
}
catch (Exception ex)
{
 // Handle exception
}

As of version 10.2 the WPF SDK provides support for two async patterns: event-based; and Task-based. In contrast, the .NET SDK primarily only supports the Task-based approach and therefore taking advantage of Tasks in your code today will not only simplify your async code but will also greatly simplify porting your code to the new API in the future.

3. Use the ‘using’ directive rather than fully qualifying the namespace

This is a simple tip and one that many of you probably already do, but it is worth noting because it will save you time. Many of the types in the new Windows Desktop API share the same class name as their equivalent in the existing WPF API. but use new namespaces. Therefore, by taking advantage of the using directive you can remove the ESRI.ArcGIS.Client.* assemblies from your project, add the new Esri.ArcGISRuntime.* assemblies, update the namespaces and your code will recompile successfully. In reality there are various differences across the API which make it unlikely your code will recompile without at least a few minor changes, but this advice will definitely speed up the migration process. For more information please see using Directive (C# Reference).

In your code, wherever possible, we recommend you avoid fully qualifying the namespace of each type and instead take advantage of the ‘using’ directive, for example:

using ESRI.ArcGIS.Client.Tasks;
…
namespace MyNamespace
{
    public partial class MainWindow : Window
    {
        QueryTask myQueryTask = new QueryTask();
        …
    }
}

When the time comes to migrate to the new Windows Desktop API you can simply swap the namespaces:

using Esri.ArcGISRuntime.Tasks.Query;
…
namespace MyNamespace
{
    public partial class MainWindow : Window
    {
        QueryTask myQueryTask = new QueryTask();
        …
    }
}

If you are planning to migrate an app you have built with the existing WPF SDK to the new .NET SDK, following these three tips will help you get your source code in good shape for migration. Once the beta is released, we really hope you can spend some time testing the new SDK and giving us feedback on what you like, what you don’t like and any issues you find. We really appreciate all your feedback, no matter how small.

This entry was posted in Developer. Bookmark the permalink.

Leave a Reply

2 Comments

  1. shohei_kusano says:

    Thank you for this blog post. I’m planning to migrate my project from the existing WPF SDK to the new .NET SDK, so this is very helpful.
    I’m assuming that at a some point Esri will stop supporting the existing WPF SDK and all users will need to migrate to the new .NET SDK. Could you please make an announcement about how long is Esri going to support the current existing WPF SDK (ex: 2yrs, 5yrs)? This information would be very helpful as I need to prepare the development resources and budget for the migration.

    Thanks,
    Shohei

    • mbranscomb says:

      Hi,

      I am glad you found the post helpful. Regarding future support, you can find information on Esri Product Lifecycles at http://support.esri.com/en/content/productlifecycles and specific information on the policy in http://downloads2.esri.com/support/TechArticles/ProductLifeCycle.pdf.

      The life cycle involves three phases of support: General Availability, Extended Support, Mature Support and eventually Retirement. The details of each phase can be found in the links above. Each of the three phases is expected to last two years, therefore the total lifecycle for a specific release should be six years.

      The focus of development work on the next release of the WPF SDK will be quality and performance improvements and compatibility with the ArcGIS system. New ArcGIS Runtime capabilities will be made available in the ArcGIS Runtime SDK for .NET.

      Cheers