Select to view content in your preferred language

How to edit a table from local map package?

2578
7
11-15-2011 10:54 AM
gangzhong
Emerging Contributor
Hi, All,

The question is about how to edit a table from mpk which is based on a file GDB.

I tried to create a local map service with feature layer, but get an error saying it is a table, but not a feature layer.

I notice a table layer in the published map services is a Joson format. I want to know what is the best way to write a new record to a table inside Runtime and how to read out the coded values out of a table easily?

Thanks,

Gang


Attached code:
localFeatureService = new LocalFeatureService()
            {
                Path = @"C:\temp\testRuntime\Data\CrashReporter.mpk"              
            };
            localFeatureService.StartAsync(x =>
            {
                _LocalFeatureLayer = new ArcGISLocalFeatureLayer()
                {
                    LayerId = 1, // a table
                    Service = localFeatureService,
                    ID = "EditLayer",                
                    Editable = true,
                    AutoSave = false,
                    Mode = FeatureLayer.QueryMode.Snapshot,
                    DisableClientCaching = true,
                    OutFields = new ESRI.ArcGIS.Client.Tasks.OutFields() { "*" },
                };

                ESRI.ArcGIS.Client.Geometry.Envelope initialExtent =
                                    new ESRI.ArcGIS.Client.Geometry.Envelope(
                           new MapPoint(-8642235.3, 5329542.9),
                           new MapPoint(-8641082.8, 5330365.3));
               initialExtent.SpatialReference = new SpatialReference(102100);
               MapControl.Extent = initialExtent;

             MapControl.Layers.Add(_LocalFeatureLayer);
0 Kudos
7 Replies
MichaelBranscomb
Esri Frequent Contributor
Hi,


## 1. Coded Value Domains ##

The following information comes from a blog post which details how you can utilize coded values for a domain defined on attribute fields in geodatabase for display at runtime (e.g. in MapTips, DataGrids, etc.).  Information about a feature layer can be used to discover coded values established via a domain applied to a field.  While feature attributes contain actual data values, coded values are often used to more effectively describe and present attribute information. For example, actual data values of 1, 2, and 3 may represent New, Open, and Closed.  A domain can be used to establish more descriptive values (New, Open, Closed) for codes (1.2,3) which changing the underlying data structure.  In the ArcGIS Runtime SDK for WPF, controls such as the FeatureDataGrid and the FeatureDataForm convert actual data values into coded values for you at runtime.  The API also provides developers with a couple of utility classes to convert actual values to coded values for use in other controls or workflows.

The example below illustrates how to utilize coded values for a field in a feature layer using the CodedValueSources and CodedValueDomainConverter classes included in the API's Toolkit library (ESRI.ArcGIS.Client.Toolkit.dll).  The coded values are displayed in map tips enabled on a feature layer. In order to get started, first add references to these classes in XAML as resources:

<Grid.Resources>
    <esriToolkitUtilities:CodedValueDomainConverter x:Key="codedValueDomainConverter" />
    <esriToolkitUtilities:CodedValueSources x:Key="codedValueSourcesStatusField" />
</Grid.Resources>


The CodedValueSources instance represents a list of codes and values (descriptions) which can be populated upon feature layer initialization:

public partial class CodedValueDomainExample : UserControl
{
    CodedValueSources codedValueSourcesStatusField;

    public CodedValueDomainExample()
    {
        InitializeComponent();

        codedValueSourcesStatusField = LayoutRoot.Resources["codedValueSourcesStatusField"] as CodedValueSources;
    }

    private void FeatureLayer_Initialized(object sender, EventArgs e)
    {
        FeatureLayer flayer = sender as FeatureLayer;
        foreach (Field field in flayer.LayerInfo.Fields)
        {
            if (field.Name == "status")
            {
                CodedValueDomain codedValueDomain = field.Domain as CodedValueDomain;

                foreach (KeyValuePair<object, string> codeVal in
                    codedValueDomain.CodedValues)
                    codedValueSourcesStatusField.Add(new CodedValueSource()
                    {
                        Code = codeVal.Key,
                        Name = codeVal.Value == null ? "" : codeVal.Value
                    });
                break;
            }
        }
    }
}


And finally, establish a binding to the attribute field on which a domain�??s coded values should be used. The CodedValueDomainConverter will convert actual data values to coded values present in the CodedValueSources instance:

<esri:FeatureLayer 
        Url="http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/SanFrancisco/311Incidents/FeatureServer/0"
        OutFields="req_type, status" 
        Mode="OnDemand"
        Initialized="FeatureLayer_Initialized">
    <esri:FeatureLayer.MapTip>
        <Border CornerRadius="10" Background="Azure" BorderBrush="Black" BorderThickness="2">
            <StackPanel Margin="5">
                <TextBlock Text="{Binding [req_type]}" FontWeight="Bold" />
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="Incident Status: " />
                    <TextBlock Text="{Binding [status],
                        Converter={StaticResource codedValueDomainConverter}, 
                        ConverterParameter={StaticResource codedValueSourcesStatusField}}" />
                </StackPanel>
            </StackPanel>
        </Border>
    </esri:FeatureLayer.MapTip>
</esri:FeatureLayer>



## 2. Editing Tables ##

If you looking for a UI control approach then you can use the FeatureDataForm in the toolkit assembly. The FeatureDataForm adjusts its field container based on the field type. For example, a coded-value domain will use ComboBox instead of TextBox, a DateTime will use DateTimePicker. Attribute values are also converted to their corresponding type. Validation and saving edits are handled by the FeatureDataForm. Alternatively you can edit tables directly in the same way you would edit a feature layer �?? you just omit a geometry. Here�??s some sample code from a colleague to help work with LayerInfo.Fields and/or FeatureTemplate/PrototypeAttributes:

var graphic = new Graphic();
if (l.LayerInfo == null) return;
//use LayerInfo.Fields 
foreach (var field in l.LayerInfo.Fields)
 graphic.Attributes[field.Name] = null;
//use PrototypeAttributes
FeatureTemplate featureTemplate = null;
if (l.LayerInfo.Templates != null && l.LayerInfo.Templates.Count > 0)
 featureTemplate = l.LayerInfo.Templates.FirstOrDefault().Value;
else if (l.LayerInfo.FeatureTypes != null && l.LayerInfo.FeatureTypes.Count > 0)
{
 var featureType = l.LayerInfo.FeatureTypes.FirstOrDefault();
 if (featureType.Value != null && featureType.Value.Templates != null)
  featureTemplate = featureType.Value.Templates.FirstOrDefault().Value;
}
if (featureTemplate != null && featureTemplate.PrototypeAttributes != null)
{
 foreach (var item in featureTemplate.PrototypeAttributes)
  graphic.Attributes[item.Key] = item.Value;
}



Cheers

Mike
0 Kudos
gangzhong
Emerging Contributor
Hi, Mike,

The main issue is how to create a feature layer based on a table from a file GDB.  I think in Runtime, the only way to editing a table is to create a feature layer for it, right?

My mpk has a feature class included  and I tried to create a feature layer based on the published map service url, but not success. See the attached code.

I noticed that the table has been published to a url such as http://127.0.0.1:50001/HZzFyC/arcgis/rest/services/crashreporter66/FeatureServer/1[/url]. That is a Json format:

{
  "capabilities": "Query,Editing,Create,Update,Delete,applyEdits,addAttachment,updateAttachment,deleteAttachments",
  "copyrightText": "",
  "currentVersion": 10.1,
  "description": "",
  "displayField": "P12_DriverName",
  "editFieldsInfo": null,
  "fields": [
    {
      "alias": "OBJECTID",
      "domain": null,
      "editable": false,
      "name": "OBJECTID",
      "nullable": false,
      "type": "esriFieldTypeOID"
    },.....
}  


Attached codes:

using System.Windows;
using ESRI.ArcGIS.Client.Local;
using ESRI.ArcGIS.Client;
using ESRI.ArcGIS.Client.Geometry;
using ESRI.ArcGIS.Client.Symbols;
using System.Windows.Media;
using ESRI.ArcGIS.Client.Tasks;
using System;
using System.Collections.Generic;

namespace test
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        ArcGISLocalFeatureLayer _LocalFeatureLayer;
        LocalFeatureService localFeatureService;
        FeatureLayer featureLayer;

        public MainWindow()
        {
            InitializeComponent();

            localFeatureService = new LocalFeatureService()
            {
                Path = @"C:\temp\testRuntime\data\CrashReporter66.mpk",
                MaxRecords = 100000
            };

            localFeatureService.StartAsync(x =>
            {
                _LocalFeatureLayer = new ArcGISLocalFeatureLayer()
                {
                    LayerId = 0,
                    Service = localFeatureService,
                    ID = "EditLayer",
                    OutFields = new ESRI.ArcGIS.Client.Tasks.OutFields() { "*" }

                };

                SimpleMarkerSymbol simpleMarkerSymbol = new SimpleMarkerSymbol()
                {
                    Color = new SolidColorBrush(System.Windows.Media.Colors.Red),
                    Size = 25,
                    Style = SimpleMarkerSymbol.SimpleMarkerStyle.Circle
                };

                _LocalFeatureLayer.Renderer = new SimpleRenderer()
                {
                    Symbol = simpleMarkerSymbol
                };

                Envelope initialExtent =
                          new ESRI.ArcGIS.Client.Geometry.Envelope(
                          new MapPoint(-8641480, 5334713.38),
                          new MapPoint(-8638008.8, 5355748.8));
                initialExtent.SpatialReference = new SpatialReference(102100);

                MapControl.Extent = initialExtent;  
                MapControl.Layers.Add(_LocalFeatureLayer);              
            });
        }
       
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            int count= _LocalFeatureLayer.Graphics.Count;

            FeatureLayer fl = new FeatureLayer();
            fl.Url = localFeatureService.UrlFeatureService +"/1";
            fl.Initialize();
            fl.Initialized += (ss, ee) =>
            {
                MessageBox.Show("Failed");  // Failed!!!
            };

        }
     
    }
}

Any more idea?
0 Kudos
DarleneBanta
Emerging Contributor
I'm also wondering how to do this.  Anyone figure this out yet?

Also how did you get the table into your map package?  Do you have to load that layer individually versus loading the entire mpk using ArcGISLocalDynamicMapServiceLayer?

Thanks!
Darlene
0 Kudos
MichaelBranscomb
Esri Frequent Contributor
Hi,

Standalone GDB tables can be included in Map Packages by adding them to your ArcMap document and sharing the map as a Map Package. You will however, need at least one feature class in the map in order for the map package to be valid. This feature class does not need to contain any features. From there, you start a LocalMapService using that MPK and then at Beta 2 you will need to use the FeatureLayer class to interact with (query/edit) the table. Since Beta 2 we have modified the ArcGISLocalFeatureLayer to also support standalone tables.

Note - to work with standalone tables you must have the FeatureLayer in Snapshot mode (or selection only). OnDemand mode does not work with FeatureLayers based on standalone tables because it uses the map extent geometry to request query the service.

Currently the HTML pages for the local server REST directory do not list the table, although it is available via the JSON e.g.:

http://localhost.:50000/RxFdMP/arcgi...eServer?f=json
http://localhost.:50000/RxFdMP/arcgi...pServer?f=json

Cheers

Mike
0 Kudos
RobertZargarian
Deactivated User
Hi All,
I am trying to edit a standalone table data from a file GDB. I did following steps without success.

1 Created an ArcMap document with som Feature classes and added some standalone tables to document. Some of the tables are related to Feature classes in .mxd.
Then I Created MPK for ArcMap doc.

2 Then I tried to add feature class and a table to map in xaml
<esri:Map x:Name="MyMap" Background="White" Extent="693502,7082101,709164,7092494" >
<esri:ArcGISLocalFeatureLayer ID="Avdelning" Path="C:\\..\test.mpk" 
                                          LayerName="Avdelning"
                                          AutoSave="False"
                                          Editable="True"
                                          OutFields="*" 
                                          Mode="OnDemand" Initialized="ArcGISLocalFeatureMapServiceLayer_Initialized" />
            <esri:ArcGISLocalFeatureLayer ID="TAVBESTAND" Path=" C:\\..\test.mpk" 
                                          LayerName="TAVBESTAND"
                                          AutoSave="False"
                                          Editable="True"
                                          OutFields="*" 
                                          Mode="Snapshot" />
</esri:Map>

Got error message:
�??A layer with name TAVBESTAND is a table and cannot be used for a FeatureLayer�?�

3 I tried to add table as LocalFeatureLayer from code behind and got the same message.

LocalFeatureService.GetServiceAsync(@"C:\..\test.mpk.mpk", (localFeatureService) =>
            {
                arcGISLocalFeatureLayer1 = new ArcGISLocalFeatureLayer()
                {
                    Service = localFeatureService, //Feature Class
                    LayerName = "Avdelning",
                    ID = "Avdelning",
                    Editable = true,
                    DisableClientCaching = true,
                    AutoSave = false,
                    Mode = ESRI.ArcGIS.Client.FeatureLayer.QueryMode.Snapshot,
                    OutFields = new OutFields() { "*" },
                };
                arcGISLocalFeatureLayer1.Initialized += (s, e) =>
                {};
                arcGISLocalFeatureLayer1.InitializationFailed += (s, e) =>
                {};
                arcGISLocalFeatureLayer1.UpdateCompleted += (s, e) =>
                {
                    MyMap.IsEnabled = true;
                };

                arcGISLocalFeatureLayer2 = new ArcGISLocalFeatureLayer()
                {
                    Service = localFeatureService, //This is a table
                    LayerName = "TAVBESTAND",
                    ID = "TAVBESTAND",
                    Editable = true,
                    Mode = ESRI.ArcGIS.Client.FeatureLayer.QueryMode.Snapshot,
                    OutFields = new OutFields() { "*" },
                };

                arcGISLocalFeatureLayer2.Initialized += (s, e) =>
                {};
                arcGISLocalFeatureLayer2.InitializationFailed += (s, e) =>
                {};
                arcGISLocalFeatureLayer2.UpdateCompleted += (s, e) =>
                {
                    MyMap.IsEnabled = true;
                };

                MyMap.Layers.Add(arcGISLocalFeatureLayer1);
                MyMap.Layers.Add(arcGISLocalFeatureLayer2);
            });

I could see that the table was published in json with URL/layernumber.
Am I doing something wrong?

Thanks!
0 Kudos
MichaelBranscomb
Esri Frequent Contributor
Hi,

In order to edit standalone tables at Beta 2 you will need to use the FeatureLayer class in conjunction with the LocalFeatureService layer Url (e.g. aLocalFeatureService.UrlFeatureService + "/0"). The ArcGISLocalFeatureLayer class had an incorrect check which results in the error message "A layer with name <X> is a table and cannot be used for a FeatureLayer". We have since corrected this behaviour.

Also - Note - to work with standalone tables you must have the FeatureLayer in Snapshot mode (or selection only). OnDemand mode does not work with FeatureLayers based on standalone tables because it uses the map extent geometry to request query the service.


Cheers

Mike
0 Kudos
RobertZargarian
Deactivated User
Thanks! Now I could add new row and edit tables.

code behind:

FeatureLayer featureLayer = new FeatureLayer()
                {
                    ID = "TAVBESTAND",
                    DisableClientCaching = true,
                    AutoSave = false,
                    Mode = ESRI.ArcGIS.Client.FeatureLayer.QueryMode.Snapshot,
                    OutFields = new OutFields() { "*" },
                    Url = localFeatureService.UrlFeatureService + "/30", //layer number
                };
0 Kudos