Skip To Content ArcGIS for Developers Sign In Dashboard

ArcGIS Runtime SDK for .NET

Dynamic Layer Edit Attribute

Download Samples Repository

Description

Demonstrates how to selectively import and update feature attributes in dynamic layer.

"Desktop" "Store" "Phone" Available for Desktop, Store, Phone

Sample Code

<UserControl x:Class="ArcGISRuntime.Samples.Desktop.DynamicLayerEditAttribute"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:esri="http://schemas.esri.com/arcgis/runtime/2013">
    <UserControl.Resources>
        <!-- Transparent symbol highlights on selection -->
        <esri:SimpleFillSymbol x:Key="TransparentFillSymbol"
                               Color="Transparent" />
        <esri:SimpleRenderer x:Key="HighlightRenderer"
                             Symbol="{StaticResource TransparentFillSymbol}" />
    </UserControl.Resources>
    <Grid>
        <esri:MapView x:Name="MyMapView"
                      MapViewTapped="MyMapView_MapViewTapped">
            <esri:Map InitialViewpoint="-13075150.8872716,4015586.5093488,-13073624.4294544,4016213.20181174">
                <esri:ArcGISTiledMapServiceLayer ServiceUri="http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer" />
                <!-- Renders features at current extent -->
                <esri:ArcGISDynamicMapServiceLayer ID="PoolPermit"
                                                   VisibleLayers="0"
                                                   ServiceUri="http://sampleserver6.arcgisonline.com/arcgis/rest/services/PoolPermits/MapServer" />
            </esri:Map>
            <esri:MapView.GraphicsOverlays>
                <!-- Highlights one feature at a time -->
                <esri:GraphicsOverlay ID="Highlighter"
                                      Renderer="{StaticResource HighlightRenderer}" />
            </esri:MapView.GraphicsOverlays>
        </esri:MapView>
        <!-- Used for attribute editing -->
        <Border x:Name="AttributeEditor"
                Visibility="Collapsed"
                Background="White"
                BorderBrush="Black"
                BorderThickness="1"
                HorizontalAlignment="Right"
                VerticalAlignment="Top"
                Margin="30"
                Padding="20">
            <Border.Effect>
                <DropShadowEffect />
            </Border.Effect>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Margin="2"
                               VerticalAlignment="Center"
                               Text="Has_Pool" />
                    <ComboBox x:Name="ChoiceList"
                              Margin="2">
                        <ComboBox.ItemTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding Value}" />
                            </DataTemplate>
                        </ComboBox.ItemTemplate>
                    </ComboBox>
                </StackPanel>
        </Border>
        <Border Background="White"
                BorderBrush="Black"
                BorderThickness="1"
                HorizontalAlignment="Left"
                VerticalAlignment="Top"
                Margin="30"
                Padding="20">
            <Border.Effect>
                <DropShadowEffect />
            </Border.Effect>
            <TextBlock Text="Click on a feature to select and edit its attribute."
                       Width="200"
                       TextAlignment="Left"
                       Margin="30,20,20,30"
                       TextWrapping="Wrap" />
        </Border>
    </Grid>
</UserControl>
using Esri.ArcGISRuntime.Controls;
using Esri.ArcGISRuntime.Data;
using Esri.ArcGISRuntime.Layers;
using Esri.ArcGISRuntime.Tasks.Query;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;

namespace ArcGISRuntime.Samples.Desktop
{
    /// <summary>
    /// Demonstrates how to selectively import and update feature attributes in dynamic layer.
    /// </summary>
    /// <title>Dynamic Layer Edit Attribute</title>
    /// <category>Editing</category>
    public partial class DynamicLayerEditAttribute : UserControl
    {
        // Editing is done through this table.
        private ServiceFeatureTable table;
        // Used to populate choice list for editing field.
        private IReadOnlyDictionary<object, string> choices;

        public DynamicLayerEditAttribute()
        {
            InitializeComponent();
        }
        
        /// <summary>
        /// Identifies feature to highlight.
        /// </summary>
        private async void MyMapView_MapViewTapped(object sender, MapViewInputEventArgs e)
        {
            // Get current viewpoints extent from the MapView
            var currentViewpoint = MyMapView.GetCurrentViewpoint(ViewpointType.BoundingGeometry);
            var viewpointExtent = currentViewpoint.TargetGeometry.Extent;

            var layer = MyMapView.Map.Layers["PoolPermit"] as ArcGISDynamicMapServiceLayer;
            var task = new IdentifyTask(new Uri(layer.ServiceUri));
            var mapPoint = MyMapView.ScreenToLocation(e.Position);
            var parameter = new IdentifyParameters(mapPoint, viewpointExtent, 2, (int)MyMapView.ActualHeight, (int)MyMapView.ActualWidth);

            // Clears map of any highlights.
            var overlay = MyMapView.GraphicsOverlays["Highlighter"] as GraphicsOverlay;
            overlay.Graphics.Clear();

            SetAttributeEditor();

            string message = null;
            try
            {
                // Performs an identify and adds feature result as selected into overlay.
                var result = await task.ExecuteAsync(parameter);
                if (result == null || result.Results == null || result.Results.Count < 1)
                    return;
                var graphic = (Graphic)result.Results[0].Feature;
                graphic.IsSelected = true;
                overlay.Graphics.Add(graphic);

                // Prepares attribute editor.
                var featureID = Convert.ToInt64(graphic.Attributes["OBJECTID"], CultureInfo.InvariantCulture);
                var hasPool = Convert.ToString(graphic.Attributes["Has_Pool"], CultureInfo.InvariantCulture);
                if (choices == null)
                    choices = await GetChoicesAsync();
                SetAttributeEditor(featureID, hasPool);
            }
            catch (Exception ex)
            {
                message = ex.Message;
            }
            if (!string.IsNullOrWhiteSpace(message))
                MessageBox.Show(message);
        }

        /// <summary>
        /// Returns choice list for attribute editing.
        /// </summary>
        private async Task<IReadOnlyDictionary<object, string>> GetChoicesAsync()
        {
            var layer = MyMapView.Map.Layers["PoolPermit"] as ArcGISDynamicMapServiceLayer;
            var id = layer.VisibleLayers[0];
            string message = null;
            try
            {
                // Gets service metadata for specific layer and extract field information for attribute editing.
                var details = await layer.GetDetailsAsync(id);
                if (details != null && details.Fields != null)
                {
                    var field = details.Fields.FirstOrDefault(f => f.Name == "has_pool");
                    if (field.Domain is CodedValueDomain)
                        return ((CodedValueDomain)field.Domain).CodedValues;
                }
            }
            catch (Exception ex)
            {
                message = ex.Message;
            }
            if (!string.IsNullOrWhiteSpace(message))
                MessageBox.Show(message);
            return null;
        }

        /// <summary>        
        /// Prepares attribute editor for editing.
        /// </summary>
        private void SetAttributeEditor(long featureID = 0, string hasPool = null)
        {
            if (ChoiceList.ItemsSource == null && choices != null)
                ChoiceList.ItemsSource = choices;
            if (!string.IsNullOrWhiteSpace(hasPool) && choices != null)
            {
                var selected = choices.FirstOrDefault(item => string.Equals(item.Value, hasPool));
                ChoiceList.SelectedItem = selected;
            }
            AttributeEditor.Tag = featureID;
            AttributeEditor.Visibility = featureID == 0 ? Visibility.Collapsed : Visibility.Visible;
            if(featureID > 0)
                ChoiceList.SelectionChanged += ChoiceList_SelectionChanged;
        }
                
        /// <summary>
        /// Enables attribute editing, submits attribute edit back to the server and refreshes dynamic layer.
        /// </summary>
        private async void ChoiceList_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ChoiceList.SelectionChanged -= ChoiceList_SelectionChanged;
            var featureID = (Int64)AttributeEditor.Tag;
            var selected = (KeyValuePair<object, string>)ChoiceList.SelectedItem;
            var layer = MyMapView.Map.Layers["PoolPermit"] as ArcGISDynamicMapServiceLayer;
            var overlay = MyMapView.GraphicsOverlays["Highlighter"] as GraphicsOverlay;
            string message = null;
            try
            {
                if (table == null)
                {
                    // Creates table based on visible layer of dynamic layer 
                    // using FeatureServer specifying has_pool field to enable editing.
                    var id = layer.VisibleLayers[0];
                    var url = layer.ServiceUri.Replace("MapServer", "FeatureServer");
                    url = string.Format("{0}/{1}", url, id);
                    table = await ServiceFeatureTable.OpenAsync(new Uri(url), null, MyMapView.SpatialReference);
                    table.OutFields = new OutFields(new string[] { "has_pool" });
                }
                // Retrieves feature identified by ID and updates its attributes.
                var feature = await table.QueryAsync(featureID);
                feature.Attributes["has_pool"] = selected.Key;
                await table.UpdateAsync(feature);
                if (table.HasEdits)
                {
                    // Pushes attribute edits back to the server.
                    var result = await table.ApplyEditsAsync();
                    if (result.UpdateResults == null || result.UpdateResults.Count < 1)
                        return;
                    var updateResult = result.UpdateResults[0];
                    if (updateResult.Error != null)
                        message = updateResult.Error.Message;
                    // Refreshes layer to reflect attribute edits.
                    layer.Invalidate();
                }
            }
            catch (Exception ex)
            {
                message = ex.Message;
            }
            finally
            {
                overlay.Graphics.Clear();
                SetAttributeEditor();
            }
            if (!string.IsNullOrWhiteSpace(message))
                MessageBox.Show(message);
        }
    }
}
Feedback on this topic?