private async void TakeMapOfflineButton_Click(object sender, EventArgs e)
        {
            // Show the loading indicator.
            _loadingIndicator.StartAnimating();

            // 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.
            string packagePath = Path.Combine(tempPath, @"NapervilleWaterNetwork");
            int    num         = 1;

            while (Directory.Exists(packagePath))
            {
                packagePath = Path.Combine(tempPath, @"NapervilleWaterNetwork" + num);
                num++;
            }

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

            // Show the loading overlay while the job is running.
            _statusLabel.Text = "Taking map offline...";

            // Create an offline map task with the current (online) map.
            OfflineMapTask takeMapOfflineTask = await OfflineMapTask.CreateAsync(_myMapView.Map);

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

            // Configure basemap settings for the job.
            ConfigureOfflineJobForBasemap(parameters, async() =>
            {
                try
                {
                    // Create the job with the parameters and output location.
                    _generateOfflineMapJob = takeMapOfflineTask.GenerateOfflineMap(parameters, packagePath);

                    // 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.
                        UIAlertController messageAlert = UIAlertController.Create("Error", "Failed to take the map offline.", UIAlertControllerStyle.Alert);
                        messageAlert.AddAction(UIAlertAction.Create("OK", UIAlertActionStyle.Default, null));
                        PresentViewController(messageAlert, true, null);
                    }

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

                        // Show layer errors.
                        UIAlertController messageAlert = UIAlertController.Create("Error", errorBuilder.ToString(), UIAlertControllerStyle.Alert);
                        messageAlert.AddAction(UIAlertAction.Create("OK", UIAlertActionStyle.Default, null));
                        PresentViewController(messageAlert, true, null);
                    }

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

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

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

                    // Change the title and disable the "Take map offline" button.
                    _statusLabel.Text             = "Map is offline";
                    _takeMapOfflineButton.Enabled = false;
                }
                catch (TaskCanceledException)
                {
                    // Generate offline map task was canceled.
                    UIAlertController messageAlert = UIAlertController.Create("Canceled", "Taking map offline was canceled", UIAlertControllerStyle.Alert);
                    messageAlert.AddAction(UIAlertAction.Create("OK", UIAlertActionStyle.Default, null));
                    PresentViewController(messageAlert, true, null);
                }
                catch (Exception ex)
                {
                    // Exception while taking the map offline.
                    UIAlertController messageAlert = UIAlertController.Create("Error", ex.Message, UIAlertControllerStyle.Alert);
                    messageAlert.AddAction(UIAlertAction.Create("OK", UIAlertActionStyle.Default, null));
                    PresentViewController(messageAlert, true, null);
                }
                finally
                {
                    // Hide the loading overlay when the job is done.
                    _loadingIndicator.StopAnimating();
                }
            });
        }
Exemple #2
0
        private async void TakeMapOfflineButton_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
        {
            // Create a new folder for the output mobile map.
            string packagePath = Path.Combine(Environment.ExpandEnvironmentVariables("%TEMP%"), @"NapervilleWaterNetwork");
            int    num         = 1;

            while (Directory.Exists(packagePath))
            {
                packagePath = Path.Combine(Environment.ExpandEnvironmentVariables("%TEMP%"), @"NapervilleWaterNetwork" + num.ToString());
                num++;
            }

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

            try
            {
                // Show the progress indicator while the job is running.
                busyIndicator.Visibility = Windows.UI.Xaml.Visibility.Visible;

                // Create an offline map task with the current (online) map.
                OfflineMapTask takeMapOfflineTask = await OfflineMapTask.CreateAsync(MyMapView.Map);

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

                // Create the job with the parameters and output location.
                _generateOfflineMapJob = takeMapOfflineTask.GenerateOfflineMap(parameters, packagePath);

                // 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)
                {
                    MessageDialog dialog = new MessageDialog("Generate offline map package failed.", "Job status");
                    await dialog.ShowAsync();

                    busyIndicator.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
                }

                // 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(string.Format("{0} : {1}", layerError.Key.Id, layerError.Value.Message));
                    }

                    // Show layer errors.
                    string        errorText = errorBuilder.ToString();
                    MessageDialog dialog    = new MessageDialog(errorText, "Layer errors");
                    await dialog.ShowAsync();
                }

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

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

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

                // Hide the "Take map offline" button.
                takeOfflineArea.Visibility = Windows.UI.Xaml.Visibility.Collapsed;

                // Show a message that the map is offline.
                messageArea.Visibility = Windows.UI.Xaml.Visibility.Visible;
            }
            catch (TaskCanceledException)
            {
                // Generate offline map task was canceled.
                MessageDialog dialog = new MessageDialog("Taking map offline was canceled");
                await dialog.ShowAsync();
            }
            catch (Exception ex)
            {
                // Exception while taking the map offline.
                MessageDialog dialog = new MessageDialog(ex.Message, "Offline map error");
                await dialog.ShowAsync();
            }
            finally
            {
                // Hide the activity indicator when the job is done.
                busyIndicator.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
            }
        }
Exemple #3
0
        private async void TakeMapOfflineButton_Click(object sender, EventArgs e)
        {
            // Clean up any previous outputs in the temp directory.
            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.
            string 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
            {
                // Show the progress indicator while the job is running.
                busyIndicator.IsVisible = true;

                // Create an offline map task with the current (online) map.
                OfflineMapTask takeMapOfflineTask = await OfflineMapTask.CreateAsync(MyMapView.Map);

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

                // Create the job with the parameters and output location.
                _generateOfflineMapJob = takeMapOfflineTask.GenerateOfflineMap(parameters, packagePath);

                // 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)
                {
                    await Application.Current.MainPage.DisplayAlert("Alert", "Generate offline map package failed.", "OK");

                    busyIndicator.IsVisible = false;
                }

                // 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(string.Format("{0} : {1}", layerError.Key.Id, layerError.Value.Message));
                    }

                    // Show layer errors.
                    string errorText = errorBuilder.ToString();
                    await Application.Current.MainPage.DisplayAlert("Alert", errorText, "OK");
                }

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

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

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

                // Hide the "Take map offline" button.
                takeOfflineArea.IsVisible = false;

                // Show a message that the map is offline.
                messageArea.IsVisible = true;
            }
            catch (TaskCanceledException)
            {
                // Generate offline map task was canceled.
                await Application.Current.MainPage.DisplayAlert("Alert", "Taking map offline was canceled", "OK");
            }
            catch (Exception ex)
            {
                // Exception while taking the map offline.
                await Application.Current.MainPage.DisplayAlert("Alert", ex.Message, "OK");
            }
            finally
            {
                // Hide the activity indicator when the job is done.
                busyIndicator.IsVisible = false;
            }
        }
Exemple #4
0
        /// <summary>
        /// Handles download job status changes when download succeeds or fails
        /// </summary>
        private async void GenerateOfflineMapJob_JobChanged(object sender, EventArgs e)
        {
            // If the job succeeded, check for layer and table errors
            // if job fails, get the error
            if (GenerateOfflineMapJob.Status == JobStatus.Succeeded)
            {
                // remove event handler so it doesn't fire multiple times
                GenerateOfflineMapJob.JobChanged -= GenerateOfflineMapJob_JobChanged;

                try
                {
                    var result = await GenerateOfflineMapJob.GetResultAsync();

                    // download has succeeded and there were no errors, return
                    if (result.LayerErrors.Count == 0 && result.TableErrors.Count == 0)
                    {
                        BroadcastMessenger.Instance.RaiseBroadcastMessengerValueChanged(true, BroadcastMessageKey.SyncSucceeded);
                    }
                    else
                    {
                        // if there were errors, create the error message to display to the user
                        var stringBuilder = new StringBuilder();

                        foreach (var error in result.LayerErrors)
                        {
                            stringBuilder.AppendLine(error.Value.Message);
                        }

                        foreach (var error in result.TableErrors)
                        {
                            stringBuilder.AppendLine(error.Value.Message);
                        }

                        UserPromptMessenger.Instance.RaiseMessageValueChanged(
                            Resources.GetString("DownloadWithErrors_Title"), stringBuilder.ToString()
                            , true, null);
                        BroadcastMessenger.Instance.RaiseBroadcastMessengerValueChanged(true, BroadcastMessageKey.SyncSucceeded);
                    }
                }
                catch (Exception ex)
                {
                    UserPromptMessenger.Instance.RaiseMessageValueChanged(
                        Resources.GetString("GenericError_Title"),
                        ex.Message,
                        true,
                        ex.StackTrace);
                }
            }
            else if (GenerateOfflineMapJob.Status == JobStatus.Failed)
            {
                // remove event handler so it doesn't fire multiple times
                GenerateOfflineMapJob.JobChanged -= GenerateOfflineMapJob_JobChanged;

                // if the job failed but not due to user cancellation, display the error
                if (GenerateOfflineMapJob.Error != null &&
                    GenerateOfflineMapJob.Error.Message != "User canceled: Job canceled.")
                {
                    UserPromptMessenger.Instance.RaiseMessageValueChanged(
                        Properties.Resources.GetString("DownloadFailed_Title"), GenerateOfflineMapJob.Error.Message, true, GenerateOfflineMapJob.Error.StackTrace);
                }
                BroadcastMessenger.Instance.RaiseBroadcastMessengerValueChanged(false, BroadcastMessageKey.SyncSucceeded);
            }
        }
        private async void GenerateOnDemand()
        {
            ArcGISPortal portal = await ArcGISPortal.CreateAsync();

            // Get a web map item using its ID.
            PortalItem webmapItem = await PortalItem.CreateAsync(portal, "dba73588a56d476484b8d0fa1c480c9b");

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

            // Create an OfflineMapTask from the map ...
            OfflineMapTask takeMapOfflineTask = await OfflineMapTask.CreateAsync(onlineMap);

            // ... or a web map portal item.
            takeMapOfflineTask = await OfflineMapTask.CreateAsync(webmapItem);

            await onlineMap.LoadAsync();

            // Create default parameters for the task.
            Envelope areaOfInterest = GetAreaOfInterest();
            GenerateOfflineMapParameters parameters = await takeMapOfflineTask.CreateDefaultGenerateOfflineMapParametersAsync(areaOfInterest);

            // Limit the maximum scale to 5000 but take all the scales above (use default of 0 as the MinScale).
            parameters.MaxScale = 5000;

            // Set attachment options.
            parameters.AttachmentSyncDirection     = AttachmentSyncDirection.Upload;
            parameters.ReturnLayerAttachmentOption = ReturnLayerAttachmentOption.EditableLayers;

            // Request the table schema only (existing features won’t be included).
            parameters.ReturnSchemaOnlyForEditableLayers = true;

            // Update the map title to contain the region.
            parameters.ItemInfo.Title = parameters.ItemInfo.Title + " (Central)";

            // Override the thumbnail with a new image based on the extent.
            RuntimeImage thumbnail = await MyMapView.ExportImageAsync();

            parameters.ItemInfo.Thumbnail = thumbnail;

            // Create the job to generate an offline map, pass in the parameters and a path to store the map package.
            GenerateOfflineMapJob generateMapJob = takeMapOfflineTask.GenerateOfflineMap(parameters, pathToOutputPackage);

            // Generate the offline map and download it.
            GenerateOfflineMapResult offlineMapResult = await generateMapJob.GetResultAsync();

            if (!offlineMapResult.HasErrors)
            {
                // Job completed successfully and all content was generated.
                Debug.WriteLine("Map " +
                                offlineMapResult.MobileMapPackage.Item.Title +
                                " was saved to " +
                                offlineMapResult.MobileMapPackage.Path);

                // Show the offline map in a MapView.
                MyMapView.Map = offlineMapResult.OfflineMap;
            }
            else
            {
                // Job is finished but one or more layers or tables had errors.
                if (offlineMapResult.LayerErrors.Count > 0)
                {
                    // Show layer errors.
                    foreach (var layerError in offlineMapResult.LayerErrors)
                    {
                        Debug.WriteLine("Error occurred when taking " +
                                        layerError.Key.Name +
                                        " offline. Error : " +
                                        layerError.Value.Message);
                    }
                }
                if (offlineMapResult.TableErrors.Count > 0)
                {
                    // Show table errors.
                    foreach (var tableError in offlineMapResult.TableErrors)
                    {
                        Debug.WriteLine("Error occurred when taking " +
                                        tableError.Key.TableName +
                                        " offline. Error : " +
                                        tableError.Value.Message);
                    }
                }
            }

            OfflineMapCapabilities results = await takeMapOfflineTask.GetOfflineMapCapabilitiesAsync(parameters);

            if (results.HasErrors)
            {
                // Handle possible errors with layers
                foreach (var layerCapability in results.LayerCapabilities)
                {
                    if (!layerCapability.Value.SupportsOffline)
                    {
                        Debug.WriteLine(layerCapability.Key.Name + " cannot be taken offline. Error : " + layerCapability.Value.Error.Message);
                    }
                }

                // Handle possible errors with tables
                foreach (var tableCapability in results.TableCapabilities)
                {
                    if (!tableCapability.Value.SupportsOffline)
                    {
                        Debug.WriteLine(tableCapability.Key.TableName + " cannot be taken offline. Error : " + tableCapability.Value.Error.Message);
                    }
                }
            }
            else
            {
                // All layers and tables can be taken offline!
                MessageBox.Show("All layers are good to go!");
            }

            // Create a mobile map package from an unpacked map package folder.
            MobileMapPackage offlineMapPackage = await MobileMapPackage.OpenAsync(pathToOutputPackage);

            // Set the title from the package metadata to the UI


            // Get the map from the package and set it to the MapView
            var map = offlineMapPackage.Maps.First();

            MyMapView.Map = map;
        }
        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 async void GenerateMapArea()
        {
            try
            {
                _windowService.SetBusyMessage("Taking map offline");
                _windowService.SetBusy(true);

                string offlineDataFolder = OfflineDataStorageHelper.GetDataFolderForMap(Map);

                // If temporary data folder exists remove it
                try
                {
                    if (Directory.Exists(offlineDataFolder))
                    {
                        Directory.Delete(offlineDataFolder, true);
                    }
                }
                catch (Exception)
                {
                    // If folder can't be deleted, open a new one.
                    offlineDataFolder = Path.Combine(offlineDataFolder, DateTime.Now.Ticks.ToString());
                }

                // If temporary data folder doesn't exists, create it
                if (!Directory.Exists(offlineDataFolder))
                {
                    Directory.CreateDirectory(offlineDataFolder);
                }

                // Get area of interest as a envelope from the map view
                var areaOfInterest =
                    _mapViewService.GetCurrentViewpoint(ViewpointType.BoundingGeometry)
                    .TargetGeometry as Envelope;

                // Step 1 : Create task with the map that is taken offline
                var task = await OfflineMapTask.CreateAsync(Map);

                // Step 2 : Create parameters based on selections
                var parameters = await task.CreateDefaultGenerateOfflineMapParametersAsync(
                    areaOfInterest);

                parameters.MaxScale       = _levelsOfDetail[SelectedLevelOfDetail].Scale;
                parameters.MinScale       = 0;
                parameters.IncludeBasemap = IncludeBasemap;
                parameters.ReturnLayerAttachmentOption = ReturnLayerAttachmentOption.None;

                // Step 3 : Create job that does the work asynchronously and
                //          set progress indication
                _job = task.GenerateOfflineMap(parameters, offlineDataFolder);
                _job.ProgressChanged += GenerateOfflineMap_ProgressChanged;

                // Step 4 : Run the job and wait the results
                var results = await _job.GetResultAsync();

                if (results.HasErrors)
                {
                    string errorString = "";
                    // If one or more layers fails, layer errors are populated with corresponding errors.
                    foreach (var(key, value) in results.LayerErrors)
                    {
                        errorString += $"Error occurred on {key.Name} : {value.Message}\r\n";
                    }
                    foreach (var(key, value) in results.TableErrors)
                    {
                        errorString += $"Error occurred on {key.TableName} : {value.Message}\r\n";
                    }
                    OfflineDataStorageHelper.FlushLogToDisk(errorString, Map);
                }

                // Step 5 : Use results
                Map = results.OfflineMap;

                RefreshCommands();
            }
            catch (Exception ex)
            {
                await _windowService.ShowAlertAsync(ex.Message, "Error generating offline map");
            }
            finally
            {
                _windowService.SetBusy(false);
            }
        }