Click or drag to resize

MapItem Property

Gets the ArcGIS Item for the map.

Namespace:  Esri.ArcGISRuntime.Mapping
Assembly:  Esri.ArcGISRuntime (in Esri.ArcGISRuntime.dll) Version: 100.8.0.0
Syntax
C#
public Item Item { get; }

Property Value

Type: Item
Remarks
This is only available if the Map is associated with an ArcGIS Item, Map has been created from an item (Map(Uri) or Map(ArcGIS Item) constructor) or has been previously saved to a portal.
Examples

Android

Example Name: MobileMapSearchAndRoute

Display maps and use locators to enable search and routing offline using a Mobile Map Package.

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.Graphics;
using Android.Graphics.Drawables;
using Android.OS;
using Android.Widget;
using ArcGISRuntime.Samples.Managers;
using Esri.ArcGISRuntime.Geometry;
using Esri.ArcGISRuntime.Mapping;
using Esri.ArcGISRuntime.Symbology;
using Esri.ArcGISRuntime.Tasks.Geocoding;
using Esri.ArcGISRuntime.Tasks.NetworkAnalysis;
using Esri.ArcGISRuntime.UI;
using Esri.ArcGISRuntime.UI.Controls;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;

namespace ArcGISRuntimeXamarin.Samples.MobileMapSearchAndRoute
{
    [Activity(ConfigurationChanges = Android.Content.PM.ConfigChanges.Orientation | Android.Content.PM.ConfigChanges.ScreenSize)]
    [ArcGISRuntime.Samples.Shared.Attributes.Sample(
        "Mobile map (search and route)",
        "Map",
        "Display maps and use locators to enable search and routing offline using a Mobile Map Package.",
        "")]
    [ArcGISRuntime.Samples.Shared.Attributes.OfflineData("260eb6535c824209964cf281766ebe43")]
    public class MobileMapSearchAndRoute : Activity
    {
        // Hold references to the UI controls.
        private MapView _myMapView;
        private LinearLayout _mapListView;

        // Hold references to map resources for easy access.
        private List<Map> _maps = new List<Map>();
        private LocatorTask _packageLocator;
        private TransportationNetworkDataset _networkDataset;

        // Overlays for use in visualizing routes.
        private GraphicsOverlay _routeOverlay;
        private GraphicsOverlay _waypointOverlay;

        // Track the start and end point for route calculation.
        private MapPoint _startPoint;
        private MapPoint _endPoint;

        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);

            Title = "Mobile map (search and route)";

            CreateLayout();
            Initialize();
        }

        private async void Initialize()
        {
            // Get the path to the package on disk.
            string filePath = DataManager.GetDataFolder("260eb6535c824209964cf281766ebe43", "SanFrancisco.mmpk");

            // Open the map package.
            MobileMapPackage package = await OpenMobileMapPackage(filePath);

            // Populate the list of maps.
            foreach (Map map in package.Maps)
            {
                await map.LoadAsync();
                _maps.Add(map);
            }

            // Show the first map by default.
            _myMapView.Map = _maps.First();

            // Get the locator task from the package.
            _packageLocator = package.LocatorTask;

            // Create and add an overlay for showing a route.
            _routeOverlay = new GraphicsOverlay();
            _routeOverlay.Renderer = new SimpleRenderer
            {
                Symbol = new SimpleLineSymbol(SimpleLineSymbolStyle.Solid, System.Drawing.Color.Blue, 3)
            };
            _myMapView.GraphicsOverlays.Add(_routeOverlay);

            // Create and add an overlay for showing waypoints/stops.
            _waypointOverlay = new GraphicsOverlay();
            _myMapView.GraphicsOverlays.Add(_waypointOverlay);

            // Enable tap-to-reverse geocode and tap-to-route.
            _myMapView.GeoViewTapped += MapView_Tapped;

            // Show list of maps in the UI.
            configureMapsButtons();
        }

        private async Task<MobileMapPackage> OpenMobileMapPackage(string path)
        {
            // Open the map package.
            MobileMapPackage package = await MobileMapPackage.OpenAsync(path);

            // Load the package.
            await package.LoadAsync();

            // Return the opened package.
            return package;
        }

        private async void MapView_Tapped(object sender, GeoViewInputEventArgs e)
        {
            // Handle routing.
            try
            {
                await ProcessRouteRequest(e.Location);
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception);
                new AlertDialog.Builder(this).SetMessage("Couldn't geocode or route.").SetTitle("Error").Show();
            }
        }

        private async Task ShowGeocodeResult(MapPoint tappedPoint)
        {
            // Reverse geocode to get an address.
            IReadOnlyList<GeocodeResult> results = await _packageLocator.ReverseGeocodeAsync(tappedPoint);

            // Process the address into usable strings.
            string address = results.First().Label;

            // Show the address in a callout.
            _myMapView.ShowCalloutAt(tappedPoint, new CalloutDefinition(address));
        }

        private async Task ProcessRouteRequest(MapPoint tappedPoint)
        {
            // Clear any existing overlays.
            _routeOverlay.Graphics.Clear();
            _myMapView.DismissCallout();

            // Return if there is no network available for routing.
            if (_networkDataset == null)
            {
                await ShowGeocodeResult(tappedPoint);
                return;
            }

            // Set the start point if it hasn't been set.
            if (_startPoint == null)
            {
                _startPoint = tappedPoint;

                await ShowGeocodeResult(tappedPoint);

                // Show the start point.
                _waypointOverlay.Graphics.Add(await GraphicForPoint(_startPoint));

                return;
            }

            if (_endPoint == null)
            {
                await ShowGeocodeResult(tappedPoint);

                // Show the end point.
                _endPoint = tappedPoint;
                _waypointOverlay.Graphics.Add(await GraphicForPoint(_endPoint));

                // Create the route task from the local network dataset.
                RouteTask routingTask = await RouteTask.CreateAsync(_networkDataset);

                // Configure route parameters for the route between the two tapped points.
                RouteParameters routingParameters = await routingTask.CreateDefaultParametersAsync();
                List<Stop> stops = new List<Stop> { new Stop(_startPoint), new Stop(_endPoint) };
                routingParameters.SetStops(stops);

                // Get the first route result.
                RouteResult result = await routingTask.SolveRouteAsync(routingParameters);
                Route firstRoute = result.Routes.First();

                // Show the route on the map. Note that symbology for the graphics overlay is defined in Initialize().
                Polyline routeLine = firstRoute.RouteGeometry;
                _routeOverlay.Graphics.Add(new Graphic(routeLine));

                return;
            }

            // Reset graphics and route.
            _routeOverlay.Graphics.Clear();
            _waypointOverlay.Graphics.Clear();
            _startPoint = null;
            _endPoint = null;
        }

        private async Task<Graphic> GraphicForPoint(MapPoint point)
        {
            // Get current assembly that contains the image.
            Assembly currentAssembly = Assembly.GetExecutingAssembly();

            // Get image as a stream from the resources.
            // Picture is defined as EmbeddedResource and DoNotCopy.
            Stream resourceStream = currentAssembly.GetManifestResourceStream(
                "ArcGISRuntime.Resources.PictureMarkerSymbols.pin_star_blue.png");

            // Create new symbol using asynchronous factory method from stream.
            PictureMarkerSymbol pinSymbol = await PictureMarkerSymbol.CreateAsync(resourceStream);
            pinSymbol.Width = 60;
            pinSymbol.Height = 60;
            // The image is a pin; offset the image so that the pinpoint
            //     is on the point rather than the image's true center.
            pinSymbol.LeaderOffsetX = 30;
            pinSymbol.OffsetY = 14;
            return new Graphic(point, pinSymbol);
        }

        private void Map_Selected(Map selectedMap)
        {
            // Clear existing overlays.
            _myMapView.DismissCallout();
            _waypointOverlay.Graphics.Clear();
            _routeOverlay.Graphics.Clear();

            try
            {
                // Show the map in the view.
                _myMapView.Map = selectedMap;

                // Get the transportation network if there is one. Will be set to null otherwise.
                _networkDataset = selectedMap.TransportationNetworks.FirstOrDefault();
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception);
                new AlertDialog.Builder(this).SetMessage(exception.ToString()).SetTitle("Couldn't select map").Show();
            }
        }

        private async void configureMapsButtons()
        {
            foreach (Map map in _maps)
            {
                Button mapButton = new Button(this);
                if (map.TransportationNetworks.Any())
                {
                    mapButton.Text = $"{map.Item.Title} (✔)";
                }
                else
                {
                    mapButton.Text = $"{map.Item.Title}";
                }

                mapButton.SetTextColor(Color.Black);
                mapButton.Background = Drawable.CreateFromStream(await map.Item.Thumbnail.GetEncodedBufferAsync(), "");
                mapButton.Click += (o, e) => { Map_Selected(map); };
                _mapListView.AddView(mapButton);

                LinearLayout.LayoutParams lparams = (LinearLayout.LayoutParams)mapButton.LayoutParameters;
                lparams.SetMargins(5, 5, 0, 5);
                mapButton.LayoutParameters = lparams;
            }
        }

        private void CreateLayout()
        {
            // Create a new vertical layout for the app.
            var layout = new LinearLayout(this) { Orientation = Orientation.Vertical };

            // Add a help label.
            TextView helpLabel = new TextView(this);
            helpLabel.Text = "Tap to show address. If a network is available, you can show a route between tapped points. Maps with networks are denoted with ✔.";
            layout.AddView(helpLabel);

            // Add space for adding options for each map.
            _mapListView = new LinearLayout(this) { Orientation = Orientation.Horizontal };
            layout.AddView(_mapListView);

            // Add the map view to the layout.
            _myMapView = new MapView(this);
            layout.AddView(_myMapView);

            // Show the layout in the app.
            SetContentView(layout);
        }
    }
}
Examples

Xamarin Forms Android

Example Name: AuthorMap

Create and save a map as an ArcGIS `PortalItem` (i.e. web map).

Code example screen shot.

C#
// Copyright 2016 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 Esri.ArcGISRuntime.Mapping;
using Esri.ArcGISRuntime.Portal;
using Esri.ArcGISRuntime.Security;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Xamarin.Forms;
using Esri.ArcGISRuntime.UI;
using System.IO;


#if __IOS__
using Xamarin.Forms.Platform.iOS;
using Xamarin.Auth;
using UIKit;
#endif

#if __ANDROID__
using Android.App;
using Application = Xamarin.Forms.Application;
using Xamarin.Auth;
#endif

namespace ArcGISRuntime.Samples.AuthorMap
{
    [ArcGISRuntime.Samples.Shared.Attributes.Sample(
        "Create and save map",
        "Map",
        "This sample demonstrates how to author and save a map as an ArcGIS portal item (web map). Saving a map to arcgis.com requires an ArcGIS Online login.",
        "1. Pan and zoom to the extent you would like for your map. \n2. Choose a basemap from the list of available basemaps. \n3. Choose one or more operational layers to include. \n4. Click 'Save ...' to apply your changes. \n5. Provide info for the new portal item, such as a Title, Description, and Tags. \n6. Click 'Save Map'. \n7. After successfully logging in to your ArcGIS Online account, the map will be saved to your default folder. \n8. You can make additional changes, update the map, and then re-save to store changes in the portal item.")]
    [ArcGISRuntime.Samples.Shared.Attributes.ClassFile("SaveMapPage.xaml.cs")]
    [ArcGISRuntime.Samples.Shared.Attributes.XamlFiles("SaveMapPage.xaml")]
    public partial class AuthorMap : ContentPage, IOAuthAuthorizeHandler
    {
        // OAuth-related values ...
        // URL of the server to authenticate with (ArcGIS Online)
        private const string ArcGISOnlineUrl = "https://www.arcgis.com/sharing/rest";

        // Client ID for the app registered with the server (Portal Maps)
        public static string AppClientId = "lgAdHkYZYlwwfAhC";

        // Redirect URL after a successful authorization (configured for the Portal Maps application)
        private string _oAuthRedirectUrl = "my-ags-app://auth";

        // String array to store basemap constructor types
        private string[] _basemapTypes = {
            "Topographic",
            "Streets",
            "Imagery",
            "Oceans"
        };

        // Dictionary of operational layer names and URLs
        private Dictionary<string, string> _operationalLayerUrls = new Dictionary<string, string>
        {
            {"World Elevations", "https://sampleserver6.arcgisonline.com/arcgis/rest/services/Elevation/WorldElevations/MapServer"},
            {"World Cities", "https://sampleserver6.arcgisonline.com/arcgis/rest/services/SampleWorldCities/MapServer/" },
            {"US Census Data", "https://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer"}
        };

        public AuthorMap()
        {
            InitializeComponent();

            // call a function to initialize the app (display a map, etc.)
            Initialize();
        }

        private void Initialize()
        {
            // Call a function to create a new map with a light gray canvas basemap
            CreateNewMap();

            // Show the default OAuth settings in the entry controls
            ClientIDEntry.Text = AppClientId;
            RedirectUrlEntry.Text = _oAuthRedirectUrl;

            // Change the style of the layer list view for Android and UWP
            switch (Device.RuntimePlatform)
            {
                case Device.Android:
                    LayersList.BackgroundColor = Color.Black;
                    OAuthSettingsGrid.BackgroundColor = Color.Gray;
                    break;
                case Device.UWP:
                    LayersList.BackgroundColor = Color.FromRgba(255, 255, 255, 0.3);
                    LayersList.Margin = new Thickness(50);
                    break;
            }
        }

        private void OAuthSettingsCancel(object sender, EventArgs e)
        {
            OAuthSettingsGrid.IsVisible = false;
        }

        private void SaveOAuthSettings(object sender, EventArgs e)
        {
            var appClientId = ClientIDEntry.Text.Trim();
            var oAuthRedirectUrl = RedirectUrlEntry.Text.Trim();

            if (!String.IsNullOrWhiteSpace(appClientId) && !String.IsNullOrWhiteSpace(oAuthRedirectUrl))
            {
                AppClientId = appClientId;
                _oAuthRedirectUrl = oAuthRedirectUrl;
            }

            OAuthSettingsGrid.IsVisible = false;

            // Call a function to set up the AuthenticationManager
            UpdateAuthenticationManager();
        }

        private void LayerSelected(object sender, ItemTappedEventArgs e)
        {
            // return if null
            if (e.Item == null) { return; }

            // Handle the event when a layer item is selected (tapped) in the layer list
            string selectedItem = e.Item.ToString();

            // See if this is one of the layers in the operational layers list 
            if (_operationalLayerUrls.ContainsKey(selectedItem))
            {
                // Get the service URL from the operational layers dictionary
                string value = _operationalLayerUrls[selectedItem];

                // Call a function to add the chosen operational layer
                AddLayer(selectedItem, value);
            }
            else
            {
                // Add the chosen basemap (replace the current one)
                AddBasemap(selectedItem);
            }

            // Hide the layer list
            LayersList.IsVisible = false;
        }

        private void ShowLayerList(object sender, EventArgs e)
        {
            // See which button was used to show the list and fill it accordingly
            Button button = (Button)sender;
            if (button.Text == "Basemap")
            {
                // Show the basemap list
                LayersList.ItemsSource = _basemapTypes.ToList();
            }
            else if (button.Text == "Layers")
            {
                // Show the operational layers list (names)
                LayersList.ItemsSource = _operationalLayerUrls.Keys;
            }

            // Show the layer list view control
            LayersList.IsVisible = true;
        }

        private async void ShowSaveMapUI(object sender, EventArgs e)
        {
            // Create a SaveMapPage page for getting user input for the new web map item
            SaveMapPage mapInputForm = new SaveMapPage();

            // If an existing map, show the UI for updating the item
            Item mapItem = MyMapView.Map.Item;
            if (mapItem != null)
            {
                mapInputForm.ShowForUpdate(mapItem.Title,mapItem.Description, mapItem.Tags.ToArray());
            }

            // Handle the save button click event on the page
            mapInputForm.OnSaveClicked += SaveMapAsync;

            // Navigate to the SaveMapPage UI
            await Navigation.PushAsync(mapInputForm);
        }

        // Event handler to get information entered by the user and save the map
        private async void SaveMapAsync(object sender, SaveMapEventArgs e)
        {
            // Get the current map
            Map myMap = MyMapView.Map;

            try
            {
                // Show the progress bar so the user knows work is happening
                SaveMapProgressBar.IsVisible = true;

                // Make sure the user is logged in to ArcGIS Online
                Credential cred = await EnsureLoggedInAsync();
                AuthenticationManager.Current.AddCredential(cred);

                // Get information entered by the user for the new portal item properties
                string title = e.MapTitle;
                string description = e.MapDescription;
                string[] tags = e.Tags;

                // Apply the current extent as the map's initial extent
                myMap.InitialViewpoint = MyMapView.GetCurrentViewpoint(ViewpointType.BoundingGeometry);

                // Export the current map view for the item's thumbnail
                RuntimeImage thumbnailImage = await MyMapView.ExportImageAsync();

                // See if the map has already been saved (has an associated portal item)
                if (myMap.Item == null)
                {
                    // Get the ArcGIS Online portal (will use credential from login above)
                    ArcGISPortal agsOnline = await ArcGISPortal.CreateAsync(new Uri(ArcGISOnlineUrl));

                    // Save the current state of the map as a portal item in the user's default folder
                    await myMap.SaveAsAsync(agsOnline, null, title, description, tags, thumbnailImage);

                    // Report a successful save
                    await Application.Current.MainPage.DisplayAlert("Map Saved", "Saved '" + title + "' to ArcGIS Online!", "OK");
                }
                else
                {
                    // This is not the initial save, call SaveAsync to save changes to the existing portal item
                    await myMap.SaveAsync();

                    // Get the file stream from the new thumbnail image
                    Stream imageStream = await thumbnailImage.GetEncodedBufferAsync();

                    // Update the item thumbnail
                    ((PortalItem)myMap.Item).SetThumbnail(imageStream);
                    await myMap.SaveAsync();

                    // Report update was successful
                    await Application.Current.MainPage.DisplayAlert("Updates Saved", "Saved changes to '" + myMap.Item.Title + "'", "OK");
                }
            }
            catch (Exception ex)
            {
                // Show the exception message
                await Application.Current.MainPage.DisplayAlert("Unable to save map", ex.Message, "OK");
            }
            finally
            {
                // Hide the progress bar
                SaveMapProgressBar.IsVisible = false;
            }
        }

        private async Task<Credential> EnsureLoggedInAsync()
        {
            // Challenge the user for portal credentials (OAuth credential request for arcgis.com)
            Credential cred = null;
            CredentialRequestInfo loginInfo = new CredentialRequestInfo
            {

                // Use the OAuth implicit grant flow
                GenerateTokenOptions = new GenerateTokenOptions
                {
                    TokenAuthenticationType = TokenAuthenticationType.OAuthImplicit
                },

                // Indicate the url (portal) to authenticate with (ArcGIS Online)
                ServiceUri = new Uri(ArcGISOnlineUrl)
            };

            try
            {
                // Get the users credentials for ArcGIS Online (should have logged in when launching the page)
                cred = await AuthenticationManager.Current.GetCredentialAsync(loginInfo, false);
            }
            catch (System.OperationCanceledException)
            {
                // user canceled the login
                throw new Exception("Portal log in was canceled.");
            }

            return cred;
        }

        private void NewMapButtonClick(object sender, EventArgs e)
        {
            // Call a function to create a new map
            CreateNewMap();
        }

        private void CreateNewMap()
        {
            // Create new Map with a light gray canvas basemap
            Map myMap = new Map(Basemap.CreateLightGrayCanvas());

            // Add the Map to the MapView
            MyMapView.Map = myMap;
        }

        private void AddBasemap(string basemapName)
        {
            // Apply the chosen basemap
            switch (basemapName)
            {
                case "Topographic":
                    // Set the basemap to Topographic
                    MyMapView.Map.Basemap = Basemap.CreateTopographic();
                    break;
                case "Streets":
                    // Set the basemap to Streets
                    MyMapView.Map.Basemap = Basemap.CreateStreets();
                    break;
                case "Imagery":
                    // Set the basemap to Imagery
                    MyMapView.Map.Basemap = Basemap.CreateImagery();
                    break;
                case "Oceans":
                    // Set the basemap to Oceans
                    MyMapView.Map.Basemap = Basemap.CreateOceans();
                    break;
            }
        }

        private void AddLayer(string layerName, string url)
        {
            // See if the layer already exists, and remove it if it does
            if (MyMapView.Map.OperationalLayers.FirstOrDefault(l => l.Name == layerName) is ArcGISMapImageLayer layer)
            {
                MyMapView.Map.OperationalLayers.Remove(layer);
            }
            else
            {
                // Otherwise, add the layer
                Uri layerUri = new Uri(url);

                // Create and add a new map image layer
                layer = new ArcGISMapImageLayer(layerUri);
                layer.Name = layerName;
                layer.Opacity = 0.5;
                MyMapView.Map.OperationalLayers.Add(layer);
            }
        }

        #region OAuth
        private void UpdateAuthenticationManager()
        {
            // Define the server information for ArcGIS Online
            ServerInfo portalServerInfo = new ServerInfo
            {
                // ArcGIS Online URI
                ServerUri = new Uri(ArcGISOnlineUrl),
                // Type of token authentication to use
                TokenAuthenticationType = TokenAuthenticationType.OAuthImplicit
            };

            // Define the OAuth information
            OAuthClientInfo oAuthInfo = new OAuthClientInfo
            {
                ClientId = AppClientId,
                RedirectUri = new Uri(_oAuthRedirectUrl)
            };
            portalServerInfo.OAuthClientInfo = oAuthInfo;

            // Get a reference to the (singleton) AuthenticationManager for the app
            AuthenticationManager thisAuthenticationManager = AuthenticationManager.Current;

            // Register the ArcGIS Online server information with the AuthenticationManager
            thisAuthenticationManager.RegisterServer(portalServerInfo);

            // Create a new ChallengeHandler that uses a method in this class to challenge for credentials
            thisAuthenticationManager.ChallengeHandler = new ChallengeHandler(CreateCredentialAsync);

            // Set the OAuthAuthorizeHandler component (this class) for Android or iOS platforms
#if __ANDROID__ || __IOS__
            thisAuthenticationManager.OAuthAuthorizeHandler = this;
#endif
        }

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

            try
            {
                // IOAuthAuthorizeHandler will challenge the user for OAuth credentials
                credential = await AuthenticationManager.Current.GenerateCredentialAsync(info.ServiceUri);
            }
            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 cancelled
            if (_taskCompletionSource != null)
            {
                // Try to cancel any existing authentication task
                _taskCompletionSource.TrySetCanceled();
            }

            // Create a task completion source
            _taskCompletionSource = new TaskCompletionSource<IDictionary<string, string>>();
#if __ANDROID__ || __IOS__

#if __ANDROID__
            // Get the current Android Activity
            Activity activity = (Activity)ArcGISRuntime.Droid.MainActivity.Instance;
#endif
            // Create a new Xamarin.Auth.OAuth2Authenticator using the information passed in
            Xamarin.Auth.OAuth2Authenticator authenticator = new Xamarin.Auth.OAuth2Authenticator(
                clientId: AppClientId,
                scope: "",
                authorizeUrl: authorizeUri,
                redirectUrl: callbackUri)
            {
                ShowErrors = false
            };

            // Allow the user to cancel the OAuth attempt
            authenticator.AllowCancel = true;

            // Define a handler for the OAuth2Authenticator.Completed event
            authenticator.Completed += (sender, authArgs) =>
            {
                try
                {
#if __IOS__
                    // Dismiss the OAuth UI when complete
                    Device.BeginInvokeOnMainThread(() =>
                    {
                        var viewController = UIApplication.SharedApplication.KeyWindow.RootViewController;
                        viewController.DismissViewController(true, null);
                    });
#endif

                    // Check if the user is authenticated
                    if (authArgs.IsAuthenticated)
                    {
                        // If authorization was successful, get the user's account
                        Xamarin.Auth.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();
                }
#if __ANDROID__ 
                finally
                {
                    // Dismiss the OAuth login
                    activity.FinishActivity(99);
                }
#endif
            };

            // 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();
#if __ANDROID__ 
                        activity.FinishActivity(99);
#endif
                    }
                }

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

            // Present the OAuth UI so the user can enter user name and password
#if __ANDROID__
            var intent = authenticator.GetUI(activity);
            activity.StartActivityForResult(intent, 99);
#endif
#if __IOS__
            // Present the OAuth UI (on the app's UI thread) so the user can enter user name and password
            Device.BeginInvokeOnMainThread(() =>
            {
                var viewController = UIApplication.SharedApplication.KeyWindow.RootViewController;
                viewController.PresentViewController(authenticator.GetUI(), true, null);
            });
#endif

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

    }
}
C#
using System;
using Xamarin.Forms;

namespace ArcGISRuntime.Samples.AuthorMap
{
    public partial class SaveMapPage : ContentPage
    {
        // Raise an event so the listener can access input values when the form has been completed
        public event EventHandler<SaveMapEventArgs> OnSaveClicked;

        public SaveMapPage ()
        {
            InitializeComponent ();
        }

        // If updating an existing map item, show the existing item info and disable changing info
        public void ShowForUpdate(string title, string description, string[] tags)
        {
            // Item title
            MapTitleEntry.Text = title;
            MapTitleEntry.IsEnabled = false;

            // Item description
            MapDescriptionEntry.Text = description;
            MapDescriptionEntry.IsEnabled = false;

            // Item tags
            MapTagsEntry.Text = string.Join(",", tags);
            MapTagsEntry.IsEnabled = false;

            // Show 'Update' rather than 'Save' for button text
            SaveMapButton.Text = "Update";
        }

        // A click handler for the save map button
        private void SaveButtonClicked(object sender, EventArgs e)
        {
            try
            {
                // Get information for the new portal item
                string title =  MapTitleEntry.Text;
                string description = MapDescriptionEntry.Text;
                string[] tags = MapTagsEntry.Text.Split(',');

                // Make sure all required info was entered
                if (String.IsNullOrEmpty(title) || String.IsNullOrEmpty(description) || tags.Length == 0)
                {
                    throw new Exception("Please enter a title, description, and some tags to describe the map.");
                }

                // Create a new OnSaveMapEventArgs object to store the information entered by the user
                SaveMapEventArgs mapSavedArgs = new SaveMapEventArgs(title, description, tags);

                // Raise the OnSaveClicked event so the main activity can handle the event and save the map
                OnSaveClicked?.Invoke(this, mapSavedArgs);

                // Close the dialog
                Navigation.PopAsync();
            }
            catch (Exception ex)
            {
                // Show the exception message (dialog will stay open so user can try again)
                Application.Current.MainPage.DisplayAlert("Error", ex.Message, "OK");
            }
        }

        private void CancelButtonClicked(object sender, EventArgs e)
        {
            // If the user cancels, just navigate back to the previous page
            Navigation.PopAsync();
        }
    }

    // Custom EventArgs class for containing portal item properties when saving a map
    public class SaveMapEventArgs : EventArgs
    {
        // Portal item title
        public string MapTitle { get; set; }

        // Portal item description
        public string MapDescription { get; set; }

        // Portal item tags
        public string[] Tags { get; set; }

        public SaveMapEventArgs(string title, string description, string[] tags) : base()
        {
            MapTitle = title;
            MapDescription = description;
            Tags = tags;
        }
    }
}
XAML
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
    x:Class="ArcGISRuntime.Samples.AuthorMap.AuthorMap"
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:esriUI="clr-namespace:Esri.ArcGISRuntime.Xamarin.Forms;assembly=Esri.ArcGISRuntime.Xamarin.Forms">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <esriUI:MapView x:Name="MyMapView" Grid.Row="0" />
        <ActivityIndicator
            x:Name="SaveMapProgressBar"
            Grid.Row="1"
            IsRunning="True"
            IsVisible="False" />
        <ListView
            x:Name="LayersList"
            Grid.Row="0"
            Grid.RowSpan="2"
            IsVisible="False"
            ItemTapped="LayerSelected" />
        <Grid
            x:Name="OAuthSettingsGrid"
            Grid.Row="0"
            HorizontalOptions="Center"
            VerticalOptions="Center"
            WidthRequest="300">
            <Grid.RowDefinitions>
                <RowDefinition Height="60" />
                <RowDefinition Height="40" />
                <RowDefinition Height="40" />
                <RowDefinition />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="100" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <Label
                Grid.Row="0"
                Grid.ColumnSpan="2"
                HorizontalOptions="Center"
                Text="OAuth Settings"
                VerticalOptions="Start" />
            <Label
                Grid.Row="1"
                HorizontalOptions="End"
                Text="Client ID:"
                VerticalOptions="Center" />
            <Entry
                x:Name="ClientIDEntry"
                Grid.Row="1"
                Grid.Column="1"
                HorizontalOptions="Start"
                Placeholder="mYCl1enTiD"
                VerticalOptions="Center"
                WidthRequest="240" />
            <Label
                Grid.Row="2"
                HorizontalOptions="End"
                Text="Redirect URL:"
                VerticalOptions="Center" />
            <Entry
                x:Name="RedirectUrlEntry"
                Grid.Row="2"
                Grid.Column="1"
                HorizontalOptions="Start"
                Placeholder="http://my.redirect/url"
                VerticalOptions="Center"
                WidthRequest="240" />
            <Button
                Grid.Row="3"
                Grid.Column="0"
                Clicked="OAuthSettingsCancel"
                HorizontalOptions="End"
                Text="Cancel"
                VerticalOptions="End" />
            <Button
                Grid.Row="3"
                Grid.Column="1"
                Clicked="SaveOAuthSettings"
                HorizontalOptions="CenterAndExpand"
                Text="Use Settings"
                VerticalOptions="End" />
        </Grid>
        <Grid Grid.Row="2" Margin="5">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <Button
                Grid.Column="0"
                Clicked="ShowLayerList"
                Text="Basemap" />
            <Button
                Grid.Column="1"
                Clicked="ShowLayerList"
                Text="Layers" />
            <Button
                Grid.Column="2"
                Clicked="NewMapButtonClick"
                Text="New" />
            <Button
                Grid.Column="3"
                Clicked="ShowSaveMapUI"
                Text="Save" />
        </Grid>
    </Grid>
</ContentPage>
XAML
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage x:Class="ArcGISRuntime.Samples.AuthorMap.SaveMapPage"
             xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
  <ContentPage.Content>
    <TableView x:Name="SaveMapUI"
           Grid.Row="0"
           Intent="Form">
      <TableRoot>
        <TableSection Title="Map Information">
          <EntryCell x:Name="MapTitleEntry"
                     Label="Title:"
                     Placeholder="Required"/>
          <EntryCell x:Name="MapDescriptionEntry"
                     Label="Description:"
                     Placeholder="Required"/>
          <EntryCell x:Name="MapTagsEntry"
                     Label="Tags:"
                     Text="ArcGIS Runtime, Webmap"/>
          <ViewCell>
            <StackLayout Orientation="Horizontal"
                         HorizontalOptions="CenterAndExpand">
              <Button Text="Cancel"
                      Clicked="CancelButtonClicked"
                      Margin="20,0"/>
              <Button x:Name="SaveMapButton"
                      Text="Save"
                      Clicked="SaveButtonClicked"/>
            </StackLayout>
          </ViewCell>
        </TableSection>
      </TableRoot>
    </TableView>
  </ContentPage.Content>
</ContentPage>
See Also
Additional Examples
Hyperlink to ExampleDescription
AuthorMapCreate and save a map as an ArcGIS `PortalItem` (i.e. web map).