Click or drag to resize

PortalItemUrl Property

Gets the URL of this portal item.

Namespace:  Esri.ArcGISRuntime.Portal
Assembly:  Esri.ArcGISRuntime (in Esri.ArcGISRuntime.dll) Version: 100.9.0.0
Syntax
C#
public Uri Url { get; }

Property Value

Type: Uri
Examples

Android

Example Name: GenerateOfflineMapWithOverrides

Take a web map offline with additional options for each layer.

Code example screen shot.

C#
// Copyright 2019 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: http://www.apache.org/licenses/LICENSE-2.0
// 
// 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 Android.App;
using Android.OS;
using Android.Widget;
using ArcGISRuntime.Samples.GenerateOfflineMapWithOverrides;
using Esri.ArcGISRuntime.Geometry;
using Esri.ArcGISRuntime.Mapping;
using Esri.ArcGISRuntime.Portal;
using Esri.ArcGISRuntime.Security;
using Esri.ArcGISRuntime.Symbology;
using Esri.ArcGISRuntime.Tasks;
using Esri.ArcGISRuntime.Tasks.Offline;
using Esri.ArcGISRuntime.UI;
using Esri.ArcGISRuntime.UI.Controls;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Xamarin.Auth;
using AlertDialog = Android.App.AlertDialog;

namespace ArcGISRuntimeXamarin.Samples.GenerateOfflineMapWithOverrides
{
    [Activity(ConfigurationChanges = Android.Content.PM.ConfigChanges.Orientation | Android.Content.PM.ConfigChanges.ScreenSize)]
    [ArcGISRuntime.Samples.Shared.Attributes.Sample(
        name: "Generate offline map (overrides)",
        category: "Map",
        description: "Take a web map offline with additional options for each layer.",
        instructions: "Modify the overrides parameters:",
        tags: new[] { "LOD", "adjust", "download", "extent", "filter", "offline", "override", "parameters", "reduce", "scale range", "setting" })]
    public class GenerateOfflineMapWithOverrides : Activity, IOAuthAuthorizeHandler
    {
        // Mapview.
        private MapView _mapView;

        // Generate Button.
        private Button _takeMapOfflineButton;

        // Progress indicator.
        private AlertDialog _alertDialog;
        private ProgressBar _progressIndicator;

        // The job to generate an offline map.
        private GenerateOfflineMapJob _generateOfflineMapJob;

        // The extent of the data to take offline.
        private Envelope _areaOfInterest = new Envelope(-88.1541, 41.7690, -88.1471, 41.7720, SpatialReferences.Wgs84);

        // The ID for a web map item hosted on the server (water network map of Naperville IL).
        private const string WebMapId = "acc027394bc84c2fb04d1ed317aac674";

        // Values for taking things the map offline.
        private string _packagePath;
        private OfflineMapTask _takeMapOfflineTask;
        private GenerateOfflineMapParameters _parameters;
        private GenerateOfflineMapParameterOverrides _overrides;

        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);
            Title = "Generate offline map (overrides)";

            // Create the UI, setup the control references and execute initialization.
            CreateLayout();
            Initialize();
        }

        private void CreateLayout()
        {
            // Create the layout.
            LinearLayout layout = new LinearLayout(this)
            {
                Orientation = Orientation.Vertical
            };

            // Add the generate button.
            _takeMapOfflineButton = new Button(this)
            {
                Text = "Take map offline"
            };
            _takeMapOfflineButton.Click += TakeMapOfflineButton_Click;
            layout.AddView(_takeMapOfflineButton);

            // Add the mapview.
            _mapView = new MapView(this);
            layout.AddView(_mapView);

            // Add the layout to the view.
            SetContentView(layout);

            // Create the progress dialog display.
            _progressIndicator = new ProgressBar(this);
            _progressIndicator.SetProgress(40, true);
            AlertDialog.Builder builder = new AlertDialog.Builder(this).SetView(_progressIndicator);
            builder.SetCancelable(true);
            builder.SetMessage("Generating offline map ...");
            _alertDialog = builder.Create();
            _alertDialog.SetButton("Cancel", (s, e) => { _generateOfflineMapJob.Cancel(); });
        }

        private async void Initialize()
        {
            try
            {
                // Create the ArcGIS Online portal.
                ArcGISPortal portal = await ArcGISPortal.CreateAsync();

                // Get the Naperville water web map item using its ID.
                PortalItem webmapItem = await PortalItem.CreateAsync(portal, WebMapId);

                // Call a function to set up the AuthenticationManager for OAuth.
                SetOAuthInfo();
                var credential = await AuthenticationManager.Current.GenerateCredentialAsync(webmapItem.Url);
                AuthenticationManager.Current.AddCredential(credential);

                // Create a map from the web map item.
                Map onlineMap = new Map(webmapItem);

                // Display the map in the MapView.
                _mapView.Map = onlineMap;

                // Disable user interactions on the map (no panning or zooming from the initial extent).
                _mapView.InteractionOptions = new MapViewInteractionOptions
                {
                    IsEnabled = false
                };

                // Create a graphics overlay for the extent graphic and apply a renderer.
                SimpleLineSymbol aoiOutlineSymbol = new SimpleLineSymbol(SimpleLineSymbolStyle.Solid, System.Drawing.Color.Red, 3);
                GraphicsOverlay extentOverlay = new GraphicsOverlay
                {
                    Renderer = new SimpleRenderer(aoiOutlineSymbol)
                };
                _mapView.GraphicsOverlays.Add(extentOverlay);

                // Add a graphic to show the area of interest (extent) that will be taken offline.
                Graphic aoiGraphic = new Graphic(_areaOfInterest);
                extentOverlay.Graphics.Add(aoiGraphic);
            }
            catch (Exception ex)
            {
                // Show the exception message to the user.
                ShowStatusMessage(ex.Message);
            }
        }

        private async void TakeMapOfflineButton_Click(object sender, EventArgs e)
        {
            // Create a path for the output mobile map.
            string tempPath = $"{Path.GetTempPath()}";
            string[] outputFolders = Directory.GetDirectories(tempPath, "NapervilleWaterNetwork*");

            // Loop through the folder names and delete them.
            foreach (string dir in outputFolders)
            {
                try
                {
                    // Delete the folder.
                    Directory.Delete(dir, true);
                }
                catch (Exception)
                {
                    // Ignore exceptions (files might be locked, for example).
                }
            }

            // Create a new folder for the output mobile map.
            _packagePath = Path.Combine(tempPath, @"NapervilleWaterNetwork");
            int num = 1;
            while (Directory.Exists(_packagePath))
            {
                _packagePath = Path.Combine(tempPath, @"NapervilleWaterNetwork" + num.ToString());
                num++;
            }

            // Create the output directory.
            Directory.CreateDirectory(_packagePath);

            try
            {
                // Create an offline map task with the current (online) map.
                _takeMapOfflineTask = await OfflineMapTask.CreateAsync(_mapView.Map);

                // Create the default parameters for the task, pass in the area of interest.
                _parameters = await _takeMapOfflineTask.CreateDefaultGenerateOfflineMapParametersAsync(_areaOfInterest);

                // Get the overrides.
                _overrides = await _takeMapOfflineTask.CreateGenerateOfflineMapParameterOverridesAsync(_parameters);

                // Create the overrides UI.
                ParameterOverrideFragment overlayFragment = new ParameterOverrideFragment(_overrides, _mapView.Map);

                // Complete configuration when the dialog is closed.
                overlayFragment.FinishedConfiguring += ConfigurationContinuation;

                // Display the configuration window.
                overlayFragment.Show(FragmentManager, "");
            }
            catch (Exception ex)
            {
                // Exception while taking the map offline.
                ShowStatusMessage(ex.Message);
            }
        }

        private async void ConfigurationContinuation(object sender, EventArgs e)
        {
            try
            {
                // Show the progress dialog while the job is running.
                _alertDialog.Show();

                // Create the job with the parameters and output location.
                _generateOfflineMapJob = _takeMapOfflineTask.GenerateOfflineMap(_parameters, _packagePath, _overrides);

                // Handle the progress changed event for the job.
                _generateOfflineMapJob.ProgressChanged += OfflineMapJob_ProgressChanged;

                // Await the job to generate geodatabases, export tile packages, and create the mobile map package.
                GenerateOfflineMapResult results = await _generateOfflineMapJob.GetResultAsync();

                // Check for job failure (writing the output was denied, e.g.).
                if (_generateOfflineMapJob.Status != JobStatus.Succeeded)
                {
                    // Report failure to the user.
                    ShowStatusMessage("Failed to take the map offline.");
                }

                // Check for errors with individual layers.
                if (results.LayerErrors.Any())
                {
                    // Build a string to show all layer errors.
                    System.Text.StringBuilder errorBuilder = new System.Text.StringBuilder();
                    foreach (KeyValuePair<Layer, Exception> layerError in results.LayerErrors)
                    {
                        errorBuilder.AppendLine($"{layerError.Key.Id} : {layerError.Value.Message}");
                    }

                    // Show layer errors.
                    ShowStatusMessage(errorBuilder.ToString());
                }

                // Display the offline map.
                _mapView.Map = results.OfflineMap;

                // Apply the original viewpoint for the offline map.
                _mapView.SetViewpoint(new Viewpoint(_areaOfInterest));

                // Enable map interaction so the user can explore the offline data.
                _mapView.InteractionOptions.IsEnabled = true;

                // Change the title and disable the "Take map offline" button.
                _takeMapOfflineButton.Text = "Map is offline";
                _takeMapOfflineButton.Enabled = false;
            }
            catch (TaskCanceledException)
            {
                // Generate offline map task was canceled.
                ShowStatusMessage("Taking map offline was canceled");
            }
            catch (Exception ex)
            {
                // Exception while taking the map offline.
                ShowStatusMessage(ex.Message);
            }
            finally
            {
                _alertDialog.Dismiss();
            }
        }

        private void ShowStatusMessage(string message)
        {
            // Display the message to the user.
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.SetMessage(message).SetTitle("Alert").Show();
        }

        // Show changes in job progress.
        private void OfflineMapJob_ProgressChanged(object sender, EventArgs e)
        {
            // Get the job.
            GenerateOfflineMapJob job = sender as GenerateOfflineMapJob;

            // Dispatch to the UI thread.
            RunOnUiThread(() =>
            {
                // Show the percent complete and update the progress bar.
                string percentText = job.Progress > 0 ? job.Progress.ToString() + " %" : string.Empty;
                _progressIndicator.Progress = job.Progress;
                _alertDialog.SetMessage($"Taking map offline ({percentText}) ...");
            });
        }

        #region Authentication

        // Constants for OAuth-related values.
        // - The URL of the portal to authenticate with (ArcGIS Online).
        private const string ServerUrl = "https://www.arcgis.com/sharing/rest";

        // - The Client ID for an app registered with the server (the ID below is for a public app created by the ArcGIS Runtime team).
        private const string AppClientId = @"lgAdHkYZYlwwfAhC";

        // - A URL for redirecting after a successful authorization (this must be a URL configured with the app).
        private const string OAuthRedirectUrl = @"my-ags-app://auth";

        private void SetOAuthInfo()
        {
            // Register the server information with the AuthenticationManager.
            ServerInfo serverInfo = new ServerInfo
            {
                ServerUri = new Uri(ServerUrl),
                TokenAuthenticationType = TokenAuthenticationType.OAuthImplicit,
                OAuthClientInfo = new OAuthClientInfo
                {
                    ClientId = AppClientId,
                    RedirectUri = new Uri(OAuthRedirectUrl)
                }
            };

            // Register this server with AuthenticationManager.
            AuthenticationManager.Current.RegisterServer(serverInfo);

            // Use a function in this class to challenge for credentials.
            AuthenticationManager.Current.ChallengeHandler = new ChallengeHandler(CreateCredentialAsync);

            // Set the OAuthAuthorizeHandler component (this class) for Android or iOS platforms.
            AuthenticationManager.Current.OAuthAuthorizeHandler = this;
        }

        // ChallengeHandler function that will be called whenever access to a secured resource is attempted.
        private async Task<Credential> CreateCredentialAsync(CredentialRequestInfo info)
        {
            OAuthTokenCredential credential = null;

            try
            {
                // Create generate token options if necessary
                if (info.GenerateTokenOptions == null)
                {
                    info.GenerateTokenOptions = new GenerateTokenOptions();
                }

                // AuthenticationManager will handle challenging the user for credentials
                credential = await AuthenticationManager.Current.GenerateCredentialAsync
                (
                    info.ServiceUri,
                    info.GenerateTokenOptions
                ) as OAuthTokenCredential;
            }
            catch (TaskCanceledException) { return credential; }
            catch (Exception)
            {
                // Exception will be reported in calling function
                throw;
            }

            return credential;
        }

        #region IOAuthAuthorizationHandler implementation

        // Use a TaskCompletionSource to track the completion of the authorization.
        private TaskCompletionSource<IDictionary<string, string>> _taskCompletionSource;

        // IOAuthAuthorizeHandler.AuthorizeAsync implementation.
        public Task<IDictionary<string, string>> AuthorizeAsync(Uri serviceUri, Uri authorizeUri, Uri callbackUri)
        {
            // If the TaskCompletionSource is not null, authorization may already be in progress and should be canceled.
            if (_taskCompletionSource != null)
            {
                // Try to cancel any existing authentication task.
                _taskCompletionSource.TrySetCanceled();
            }

            // Create a task completion source.
            _taskCompletionSource = new TaskCompletionSource<IDictionary<string, string>>();

            // Get the current Android Activity.
            Activity activity = this;

            // Create a new Xamarin.Auth.OAuth2Authenticator using the information passed in.
            OAuth2Authenticator authenticator = new OAuth2Authenticator(
                clientId: AppClientId,
                scope: "",
                authorizeUrl: authorizeUri,
                redirectUrl: callbackUri)
            {
                ShowErrors = false,
                // Allow the user to cancel the OAuth attempt.
                AllowCancel = true
            };

            // Define a handler for the OAuth2Authenticator.Completed event.
            authenticator.Completed += (sender, authArgs) =>
            {
                try
                {
                    // Check if the user is authenticated.
                    if (authArgs.IsAuthenticated)
                    {
                        // If authorization was successful, get the user's account.
                        Account authenticatedAccount = authArgs.Account;

                        // Set the result (Credential) for the TaskCompletionSource.
                        _taskCompletionSource.SetResult(authenticatedAccount.Properties);
                    }
                    else
                    {
                        throw new Exception("Unable to authenticate user.");
                    }
                }
                catch (Exception ex)
                {
                    // If authentication failed, set the exception on the TaskCompletionSource.
                    _taskCompletionSource.TrySetException(ex);

                    // Cancel authentication.
                    authenticator.OnCancelled();
                }
                finally
                {
                    // Dismiss the OAuth login.
                    activity.FinishActivity(99);
                }
            };

            // If an error was encountered when authenticating, set the exception on the TaskCompletionSource.
            authenticator.Error += (sndr, errArgs) =>
            {
                // If the user cancels, the Error event is raised but there is no exception ... best to check first.
                if (errArgs.Exception != null)
                {
                    _taskCompletionSource.TrySetException(errArgs.Exception);
                }
                else
                {
                    // Login canceled: dismiss the OAuth login.
                    if (_taskCompletionSource != null)
                    {
                        _taskCompletionSource.TrySetCanceled();
                        activity.FinishActivity(99);
                    }
                }

                // Cancel authentication.
                authenticator.OnCancelled();
            };

            // Present the OAuth UI so the user can enter user name and password.
            Android.Content.Intent intent = authenticator.GetUI(activity);
            activity.StartActivityForResult(intent, 99);

            // Return completion source task so the caller can await completion.
            return _taskCompletionSource.Task;
        }

        #endregion IOAuthAuthorizationHandler implementation

        #endregion Authentication
    }
}
C#
using System;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Views;
using Android.Widget;
using Esri.ArcGISRuntime.Data;
using Esri.ArcGISRuntime.Geometry;
using Esri.ArcGISRuntime.Mapping;
using Esri.ArcGISRuntime.Tasks.Offline;
using System.Collections.Generic;
using System.Linq;

namespace ArcGISRuntime.Samples.GenerateOfflineMapWithOverrides
{
    public class ParameterOverrideFragment : DialogFragment
    {
        // Hold references to the overrides, map, and area of interest.
        private GenerateOfflineMapParameterOverrides _overrides;
        private Map _map;
        private Envelope _areaOfInterest = new Envelope(-88.1541, 41.7690, -88.1471, 41.7720, SpatialReferences.Wgs84);

        // Hold references to the UI controls.
        private SeekBar _minScaleBar;
        private SeekBar _maxScaleBar;
        private SeekBar _extentBufferBar;
        private SeekBar _maxFlowBar;
        private TextView _minScaleValueView;
        private TextView _maxScaleValueView;
        private TextView _extentBufferValueView;
        private TextView _maxFlowValueView;
        private CheckBox _serviceConnCheckbox;
        private CheckBox _sysValveCheckbox;
        private CheckBox _cropLayerCheckBox;

        public ParameterOverrideFragment()
        {
        }

        public ParameterOverrideFragment(GenerateOfflineMapParameterOverrides overrides, Map map)
        {
            _overrides = overrides;
            _map = map;
        }

        #region overrides

        private void ConfigureTileLayerOverrides(GenerateOfflineMapParameterOverrides overrides)
        {
            // Create a parameter key for the first basemap layer.
            OfflineMapParametersKey basemapKey = new OfflineMapParametersKey(_map.Basemap.BaseLayers.First());

            // Get the export tile cache parameters for the layer key.
            ExportTileCacheParameters basemapParams = overrides.ExportTileCacheParameters[basemapKey];

            // Clear the existing level IDs.
            basemapParams.LevelIds.Clear();

            // Get the min and max scale from the UI.
            int minScale = _minScaleBar.Progress;
            int maxScale =  _maxScaleBar.Progress;

            // Re-add selected scales.
            for (int i = minScale; i < maxScale; i++)
            {
                basemapParams.LevelIds.Add(i);
            }

            // Expand the area of interest based on the specified buffer distance.
            int bufferDistance = _extentBufferBar.Progress;
            basemapParams.AreaOfInterest = GeometryEngine.BufferGeodetic(_areaOfInterest, bufferDistance, LinearUnits.Meters);
        }

        private void ConfigureLayerExclusion(GenerateOfflineMapParameterOverrides overrides)
        {
            // Apply layer exclusions as specified in the UI.
            if (!_serviceConnCheckbox.Checked)
            {
                ExcludeLayerByName("Service Connection", overrides);
            }

            if (!_sysValveCheckbox.Checked)
            {
                ExcludeLayerByName("System Valve", overrides);
            }
        }

        private void CropWaterPipes(GenerateOfflineMapParameterOverrides overrides)
        {
            if (_cropLayerCheckBox.Checked)
            {
                // Get the ID of the water pipes layer.
                long targetLayerId = GetServiceLayerId(GetLayerByName("Main"));

                // For each layer option.
                foreach (GenerateLayerOption layerOption in GetAllLayerOptions(overrides))
                {
                    // If the option's LayerId matches the selected layer's ID.
                    if (layerOption.LayerId == targetLayerId)
                    {
                        layerOption.UseGeometry = true;
                    }
                }
            }
        }

        private void ApplyFeatureFilter(GenerateOfflineMapParameterOverrides overrides)
        {
            // For each layer option.
            foreach (GenerateLayerOption option in GetAllLayerOptions(overrides))
            {
                // If the option's LayerId matches the selected layer's ID.
                if (option.LayerId == GetServiceLayerId(GetLayerByName("Hydrant")))
                {
                    // Apply the where clause.
                    option.WhereClause = $"FLOW >= {_maxFlowBar.Progress}";
                    // Configure the option to use the where clause.
                    option.QueryOption = GenerateLayerQueryOption.UseFilter;
                }
            }
        }

        private IList<GenerateLayerOption> GetAllLayerOptions(GenerateOfflineMapParameterOverrides overrides)
        {
            // Find the first feature layer.
            FeatureLayer targetLayer = _map.OperationalLayers.OfType<FeatureLayer>().First();

            // Get the key for the layer.
            OfflineMapParametersKey layerKey = new OfflineMapParametersKey(targetLayer);

            // Use that key to get the generate options for the layer.
            GenerateGeodatabaseParameters generateParams = overrides.GenerateGeodatabaseParameters[layerKey];

            // Return the layer options.
            return generateParams.LayerOptions;
        }

        private void ExcludeLayerByName(string layerName, GenerateOfflineMapParameterOverrides overrides)
        {
            // Get the feature layer with the specified name.
            FeatureLayer targetLayer = GetLayerByName(layerName);

            // Get the layer's ID.
            long targetLayerId = GetServiceLayerId(targetLayer);

            // Create a layer key for the selected layer.
            OfflineMapParametersKey layerKey = new OfflineMapParametersKey(targetLayer);

            // Get the parameters for the layer.
            GenerateGeodatabaseParameters generateParams = overrides.GenerateGeodatabaseParameters[layerKey];

            // Get the layer options for the layer.
            IList<GenerateLayerOption> layerOptions = generateParams.LayerOptions;

            // Find the layer option matching the ID.
            GenerateLayerOption targetLayerOption = layerOptions.First(layer => layer.LayerId == targetLayerId);

            // Remove the layer option.
            layerOptions.Remove(targetLayerOption);
        }

        private FeatureLayer GetLayerByName(string layerName)
        {
            // Get the first map in the operational layers collection that is a feature layer with name matching layerName
            return _map.OperationalLayers.OfType<FeatureLayer>().First(layer => layer.Name == layerName);
        }

        private long GetServiceLayerId(FeatureLayer layer)
        {
            // Find the service feature table for the layer; this assumes the layer is backed by a service feature table.
            ServiceFeatureTable serviceTable = (ServiceFeatureTable) layer.FeatureTable;

            // Return the layer ID.
            return serviceTable.LayerInfo.ServiceLayerId;
        }

        #endregion overrides

        public override Dialog OnCreateDialog(Bundle savedInstanceState)
        {
            // Load the layout from the XML file.
            LayoutInflater inflater = (LayoutInflater)Activity.GetSystemService(Context.LayoutInflaterService);
            View layout = inflater.Inflate(Resource.Layout.OverrideParametersDialog, null);

            // Update the references to the UI controls.
            _minScaleBar = layout.FindViewById<SeekBar>(Resource.Id.minScaleSeekBar);
            _maxScaleBar = layout.FindViewById<SeekBar>(Resource.Id.maxScaleSeekBar);
            _extentBufferBar = layout.FindViewById<SeekBar>(Resource.Id.extentBufferDistanceSeekBar);
            _maxFlowBar = layout.FindViewById<SeekBar>(Resource.Id.minHydrantFlowRateSeekBar);

            _minScaleBar.ProgressChanged += BarValueChanged;
            _maxScaleBar.ProgressChanged += BarValueChanged;
            _extentBufferBar.ProgressChanged += BarValueChanged;
            _maxFlowBar.ProgressChanged += BarValueChanged;

            _minScaleValueView = layout.FindViewById<TextView>(Resource.Id.currMinScaleTextView);
            _maxScaleValueView = layout.FindViewById<TextView>(Resource.Id.currMaxScaleTextview);
            _extentBufferValueView = layout.FindViewById<TextView>(Resource.Id.currExtentBufferDistanceTextView);
            _maxFlowValueView = layout.FindViewById<TextView>(Resource.Id.currMinHydrantFlowRateTextView);

            _serviceConnCheckbox = layout.FindViewById<CheckBox>(Resource.Id.serviceConnectionsCheckBox);
            _sysValveCheckbox = layout.FindViewById<CheckBox>(Resource.Id.systemValvesCheckBox);
            _cropLayerCheckBox = layout.FindViewById<CheckBox>(Resource.Id.waterPipesCheckBox);

            // Show the dialog.
            var builder = new AlertDialog.Builder(Activity).SetView(layout).SetTitle("Override parameters");
            builder.SetPositiveButton("Take map offline", TakeMapOffline_Clicked);
            return builder.Create();
        }

        private void TakeMapOffline_Clicked(object sender, DialogClickEventArgs e)
        {
            // Configure the overrides using helper methods.
            ConfigureTileLayerOverrides(_overrides);
            ConfigureLayerExclusion(_overrides);
            CropWaterPipes(_overrides);
            ApplyFeatureFilter(_overrides);

            // Dismiss the dialog.
            Dismiss();

            // Raise the event.
            FinishedConfiguring?.Invoke(this, null);
        }

        private void BarValueChanged(object sender, SeekBar.ProgressChangedEventArgs e)
        {
            if (sender == _minScaleBar)
            {
                _minScaleValueView.Text = _minScaleBar.Progress.ToString();
            }
            else if (sender == _maxScaleBar)
            {
                _maxScaleValueView.Text = _maxScaleBar.Progress.ToString();
            }
            else if (sender == _extentBufferBar)
            {
                _extentBufferValueView.Text = $"{_extentBufferBar.Progress}m";
            }
            else if (sender == _maxFlowBar)
            {
                _maxFlowValueView.Text = $"{_maxFlowBar.Progress} GPM";
            }
        }

        public event EventHandler FinishedConfiguring;
    }
}
See Also