Click or drag to resize

JobTProgress Property

Gets the current progress of the job as a percentage toward completion

Namespace:  Esri.ArcGISRuntime.Tasks
Assembly:  Esri.ArcGISRuntime (in Esri.ArcGISRuntime.dll) Version: 100.11.0
public int Progress { get; }

Return Value

Type: Int32
The job's current completion percentage. Zero indicates that the job has not been started, and 100 indicates completion.


Example Name: LocalServerGeoprocessing

Create contour lines from local raster data using a local geoprocessing package `.gpk` and the contour geoprocessing tool.

Code example screen shot.

// Copyright 2018 Esri.
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
// language governing permissions and limitations under the License.

using ArcGISRuntime.Samples.Managers;
using Esri.ArcGISRuntime.LocalServices;
using Esri.ArcGISRuntime.Mapping;
using Esri.ArcGISRuntime.Tasks;
using Esri.ArcGISRuntime.Tasks.Geoprocessing;
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;

namespace ArcGISRuntime.WPF.Samples.LocalServerGeoprocessing
        name: "Local server geoprocessing",
        category: "Local Server",
        description: "Create contour lines from local raster data using a local geoprocessing package `.gpk` and the contour geoprocessing tool.",
        instructions: "Contour Line Controls (Top Left):",
        tags: new[] { "geoprocessing", "local", "offline", "parameters", "processing", "service" })]
    [ArcGISRuntime.Samples.Shared.Attributes.OfflineData("f7c7b4a30fb9415896ba0d1921fe014b", "da9e565a52ca41c1937cff1a01017068")]
    public partial class LocalServerGeoprocessing
        // Hold a reference to the local geoprocessing service
        private LocalGeoprocessingService _gpService;

        // Hold a reference to the task
        private GeoprocessingTask _gpTask;

        // Hold a reference to the job
        private GeoprocessingJob _gpJob;

        public LocalServerGeoprocessing()

            // set up the sample

        private async void Initialize()
            // Create a map and add it to the view
            MyMapView.Map = new Map(Basemap.CreateLightGrayCanvasVector());

            // Load the tiled layer and get the path
            string rasterPath = GetRasterPath();

            // Create a tile cache using the path to the raster
            TileCache myTileCache = new TileCache(rasterPath);

            // Create the tiled layer from the tile cache
            ArcGISTiledLayer tiledLayer = new ArcGISTiledLayer(myTileCache);

            // Try to load the tiled layer
                // Wait for the layer to load
                await tiledLayer.LoadAsync();

                // Zoom to extent of the tiled layer
                await MyMapView.SetViewpointGeometryAsync(tiledLayer.FullExtent);
            catch (Exception)
                MessageBox.Show("Couldn't load the tile package, ending sample load.");

            // Add the layer to the map

            // Try to start Local Server
                // LocalServer must not be running when setting the data path.
                if (LocalServer.Instance.Status == LocalServerStatus.Started)
                    await LocalServer.Instance.StopAsync();

                // Set the local data path - must be done before starting. On most systems, this will be C:\EsriSamples\AppData.
                // This path should be kept short to avoid Windows path length limitations.
                string tempDataPathRoot = Directory.GetParent(Environment.GetFolderPath(Environment.SpecialFolder.Windows)).FullName;
                string tempDataPath = Path.Combine(tempDataPathRoot, "EsriSamples", "AppData");
                Directory.CreateDirectory(tempDataPath); // CreateDirectory won't overwrite if it already exists.
                LocalServer.Instance.AppDataPath = tempDataPath;

                // Start the local server instance
                await LocalServer.Instance.StartAsync();
            catch (Exception ex)
                var localServerTypeInfo = typeof(LocalMapService).GetTypeInfo();
                var localServerVersion = FileVersionInfo.GetVersionInfo(localServerTypeInfo.Assembly.Location);

                MessageBox.Show($"Please ensure that local server {localServerVersion.FileVersion} is installed prior to using the sample. The download link is in the description. Message: {ex.Message}", "Local Server failed to start");

            // Get the path to the geoprocessing task
            string gpServiceUrl = GetGpPath();

            // Create the geoprocessing service
            _gpService = new LocalGeoprocessingService(gpServiceUrl, GeoprocessingServiceType.AsynchronousSubmitWithMapServiceResult);

            // Take action once the service loads
            _gpService.StatusChanged += GpServiceOnStatusChanged;

            // Try to start the service
                // Start the service
                await _gpService.StartAsync();
            catch (Exception)
                MessageBox.Show("geoprocessing service failed to start.");

        private async void GpServiceOnStatusChanged(object sender, StatusChangedEventArgs statusChangedEventArgs)
            // Return if the server hasn't started
            if (statusChangedEventArgs.Status != LocalServerStatus.Started) return;

            // Create the geoprocessing task from the service
            _gpTask = await GeoprocessingTask.CreateAsync(new Uri(_gpService.Url + "/Contour"));

            // Update UI
            MyUpdateContourButton.IsEnabled = true;
            MyLoadingIndicator.Visibility = Visibility.Collapsed;

        private void GenerateContours()
            // Show the progress bar
            MyLoadingIndicator.Visibility = Visibility.Visible;
            MyLoadingIndicator.IsIndeterminate = false;

            // Create the geoprocessing parameters
            GeoprocessingParameters gpParams = new GeoprocessingParameters(GeoprocessingExecutionType.AsynchronousSubmit);

            // Add the interval parameter to the geoprocessing parameters
            gpParams.Inputs["ContourInterval"] = new GeoprocessingDouble(MyContourSlider.Value);

            // Create the job
            _gpJob = _gpTask.CreateJob(gpParams);

            // Update the UI when job progress changes
            _gpJob.ProgressChanged += (sender, args) =>
                 Dispatcher.Invoke(() => { MyLoadingIndicator.Value = _gpJob.Progress; });

            // Be notified when the task completes (or other change happens)
            _gpJob.JobChanged += GpJobOnJobChanged;

            // Start the job

        private async void GpJobOnJobChanged(object o, EventArgs eventArgs)
            // Show message if job failed
            if (_gpJob.Status == JobStatus.Failed)
                MessageBox.Show("Job Failed");

            // Return if not succeeded
            if (_gpJob.Status != JobStatus.Succeeded) { return; }

            // Get the URL to the map service
            string gpServiceResultUrl = _gpService.Url.ToString();

            // Get the URL segment for the specific job results
            string jobSegment = "MapServer/jobs/" + _gpJob.ServerJobId;

            // Update the URL to point to the specific job from the service
            gpServiceResultUrl = gpServiceResultUrl.Replace("GPServer", jobSegment);

            // Create a map image layer to show the results
            ArcGISMapImageLayer myMapImageLayer = new ArcGISMapImageLayer(new Uri(gpServiceResultUrl));

            // Load the layer
            await myMapImageLayer.LoadAsync();

            // This is needed because the event comes from outside of the UI thread
            Dispatcher.Invoke(() =>
                // Add the layer to the map

                // Hide the progress bar
                MyLoadingIndicator.Visibility = Visibility.Collapsed;

                // Disable the generate button
                MyUpdateContourButton.IsEnabled = false;

                // Enable the reset button
                MyResetButton.IsEnabled = true;

        private static string GetRasterPath()
            return DataManager.GetDataFolder("f7c7b4a30fb9415896ba0d1921fe014b", "RasterHillshade.tpk");

        private static string GetGpPath()
            return DataManager.GetDataFolder("da9e565a52ca41c1937cff1a01017068", "Contour.gpk");

        private void MyResetButton_OnClick(object sender, RoutedEventArgs e)
            // Remove the contour

            // Enable the generate button
            MyUpdateContourButton.IsEnabled = true;

            // Disable the reset button
            MyResetButton.IsEnabled = false;

        private void MyUpdateContourButton_OnClick(object sender, RoutedEventArgs e)
            // Disable the generate button
            ((Button)sender).IsEnabled = false;

            // Generate the contours
<UserControl x:Class="ArcGISRuntime.WPF.Samples.LocalServerGeoprocessing.LocalServerGeoprocessing"
        <esri:MapView x:Name="MyMapView" />
        <Border Style="{StaticResource BorderStyle}">
                    <RowDefinition Height="auto" />
                    <RowDefinition Height="auto" />
                    <RowDefinition Height="auto" />
                    <RowDefinition Height="auto" />
                    <ColumnDefinition Width="2*" />
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="*" />
                    Text="Use the slider to select a contour interval (height difference between contour lines). Use the buttons to update or clear the contours."
                    Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3"
                    FontWeight="SemiBold" TextWrapping="Wrap" />
                <ProgressBar x:Name="MyLoadingIndicator"
                             Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3"
                             Height="15" Margin="0,5,0,0"
                             IsIndeterminate="True" />
                <Slider x:Name="MyContourSlider"
                        Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2"
                        VerticalAlignment="Center" Margin="0,5,0,0"
                        Minimum="50" Maximum="350" />
                <TextBlock x:Name="MyContourDepthLabel"
                           Grid.Row="2" Grid.Column="2"
                           VerticalAlignment="Center" Margin="0,5,0,0"
                           Text="{Binding Value, ElementName=MyContourSlider, StringFormat=N2}" />
                <Button x:Name="MyUpdateContourButton"
                        Grid.Row="3" Grid.Column="0"
                        Click="MyUpdateContourButton_OnClick" />
                <Button x:Name="MyResetButton"
                        Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="2"
                        Click="MyResetButton_OnClick" />
See Also
Additional Examples
Hyperlink to ExampleDescription
DownloadPreplannedMapTake a map offline using a preplanned map area.
EditAndSyncFeaturesSynchronize offline edits with a feature service.
GenerateGeodatabaseGenerate a local geodatabase from an online feature service.
GenerateOfflineMapTake a web map offline.
GenerateOfflineMapWithOverridesTake a web map offline with additional options for each layer.
LocalServerGeoprocessingCreate contour lines from local raster data using a local geoprocessing package `.gpk` and the contour geoprocessing tool.
OfflineBasemapByReferenceUse the `OfflineMapTask` to take a web map offline, but instead of downloading an online basemap, use one which is already on the device.