Work with contingent values

Contingent values are a data design feature that allow you to make values in one field dependent upon values in another field. In other words, contingent values are how you define a set of attribute values that are specifically valid in the context of other feature attribute values. For example, a power pole dataset might use contingent values to specify what values are appropriate for poles based on other attributes. The voltage level for a pole determines what material values are valid; each material might have a set of appropriate heights from which to choose. Contingent values let you define all valid combinations of values for two or more attribute fields within a dataset.

Values in the dropdown are contingent values based on the previous entry.

What contingent values look like

You can author contingent values using ArcGIS Pro and save them in a mobile map or scene package, standalone geodatabase, web map, web scene, or feature service.

Contingent values are defined in one or more field groups. A field group is a named collection of attribute fields in your dataset that have contingent values. Each field in a field group must have an associated domain. Contingent values are based on the field's domain and represent a subset of the values the domain defines. See Introduction to attribute domains in the ArcGIS Pro documentation for more information about domains.

For each field group, contingent values define all combinations of appropriate values for the participating fields. The value you provide for each field depends on the type of domain associated with it (coded value or range). You can also provide special values to indicate that any value in the domain is considered valid or that a null value is valid (for fields that accept null values). Note that the any value also includes null.

The following image shows a field group that defines a set of contingent values for power poles. The fields Voltage, Material, and Height use coded value domains for their values, while Diameter uses a range domain. Poles that have a value of Wood for the Material field can have any value for Height that's in the associated domain (or null) without violating the contingent values.

Contingent values that define all valid combinations for voltage levels, material types, pole height, and diameter.

Contingent values in ArcGIS Runtime

ArcGIS Runtime provides classes and helper methods for reading contingent value definitions for a dataset and for determining contingent value violations for a specific feature, allowing your ArcGIS Runtime app to incorporate contingent values into editing workflows. You might use drop down lists, for example, to provide the appropriate list of values based on other attributes that have been specified. Your app can also validate against contingent values to find violations before saving edits for a feature.

Contingent values can be read from an ArcGISFeatureTable. Here are some of the classes used to represent contingent values in ArcGIS Runtime API.

  • FieldGroup—Defines all possible contingent values for a set of fields. The contingent values definition contains a collection of field groups.

  • Contingency—Defines a set of contingent values for a field group.

  • ContingentValue—A base class that defines a possible value for a field participating in a field group. A contingent value can be one of the following:

In addition to these classes, the API provides the following helper methods on ArcGISFeatureTable. In many cases, these helper methods are all you need to provide contingent value support when editing the table.

Edit with contingent values

Contingent values do not enforce data integrity or attribute rules for the data. However, you can design your app to guide the user through an edit workflow where contingent values provide appropriate choices and validation checks before edits are saved. For example, you could enforce ordered steps in your editing workflow to ensure that the current set of values you display for the editor are based on the previous inputs.

Values in the dropdown are contingent values based on the previous entry.

Get contingent values

Contingent values are derived from values in an attribute domain for the dataset. Since domains can either be a list of coded values or a range of acceptable numeric values, the same is true for contingent values. Each set of contingent values is defined from a subset of the domain. If your domain for pole diameter defines a range of 6 to 18 inches, for example, any contingent values must be within this range, for example 7 to 10 inches. Likewise, coded value domains define a set of acceptable values and the contingent values must contain a subset of those items.

To get the contingent values for a field, use the ArcGISFeatureTable.GetContingentValues() helper method and pass the current feature and the field name. The helper method looks at the current values defined for other attributes of the feature to return a set of the appropriate contingent values for the specified field.

The following code gets all contingent coded values for the specified field based on the other attribute values for the provided feature.

Use dark colors for code blocks
                                                                                                                                                                                                                                                                                 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
// --- Edit ---

private async void AddFeature(MapPoint structureLocation, string type, string cause)
{
    // Create attributes for the feature.
    Dictionary<string, object> attributes = new Dictionary<string, object>();
    attributes.Add("typdamage", type);
    attributes.Add("primcause", cause);

    // Create a new feature from the attributes and the point.
    Feature newFeature = _damagePointsTable.CreateFeature(attributes, structureLocation);

    // Add the feature to the local table.
    await _damagePointsTable.AddFeatureAsync(newFeature);

    // If the feature table is a service feature table then
    // apply edits to its service geodatabase.
    ...
}



private async void UpdateFeature(ArcGISFeature arcgisFeature)
{
    // Change the feature's attribute value.
    arcgisFeature.Attributes["typdamage"] = "Inaccessible";

    // Change the feature's geometry.
    MapPoint location = arcgisFeature.Geometry as MapPoint;
    MapPoint newLocation = new MapPoint(location.X, location.Y + 50000);
    arcgisFeature.Geometry = newLocation;

    // Update the feature on the local table.
    await _damagePointsTable.UpdateFeatureAsync(f);

    // If the feature table is a service feature table then
    // apply edits to its service geodatabase.
    ...
}



private async void DeleteSelectedFeatures(FeatureLayer damageLayer)
{
    // Get all selected features in the layer.
    FeatureQueryResult selectedFeatures = await damageLayer.GetSelectedFeaturesAsync();

    // Delete the selected features.
    await _damagePointsTable.DeleteFeaturesAsync(selectedFeatures);

    // If the feature table is a service feature table then
    // apply edits to its service geodatabase.
    ...
}



// If the feature table is a service feature table, send these edits
// to the online service by applying them to its service geodatabase.
EditResult editResults = await table.ServiceGeodatabase.ApplyEditsAsync();


// --- Query ---


// Build a buffer (polygon) around a click point
var buffer = GeometryEngine.Buffer(queryPoint, 5000);

// Use the buffer to define the geometry for a query
var query = new QueryParameters();
query.Geometry = buffer;
query.SpatialRelationship = SpatialRelationship.Contains;

// Select features in a feature layer using the query
await damageLayer.SelectFeaturesAsync(query, Esri.ArcGISRuntime.Mapping.SelectionMode.New);



// TODO:



// TODO:



// TODO:



var layer = MyMapView.Map.OperationalLayers[0];
var pixelTolerance = 20;
var returnPopupsOnly = false;
var maxResults = 5;

// identify a layer using MapView, passing in the layer, the tap point, tolerance, types to return, and max results
IdentifyLayerResult idResults = await MyMapView.IdentifyLayerAsync(layer, tapScreenPoint, pixelTolerance, returnPopupsOnly, maxResults);

// get the layer identified and cast it to FeatureLayer
FeatureLayer idLayer = idResults.LayerContent as FeatureLayer;

// iterate each identified GeoElement in the results
foreach (GeoElement idElement in idResults.GeoElements)
{
    // cast the result GeoElement to Feature
    Feature idFeature = idElement as Feature;

    // select this feature in the feature layer
    idLayer.SelectFeature(idFeature);
}


// -- BRANCH VERSIONING --//


    // Get the feature table from a feature layer and cast it to ServiceFeatureTable
    // (if the table is not a ServiceFeatureTable, it will be null)
    ServiceFeatureTable table = layer.FeatureTable as ServiceFeatureTable;



    // If the feature table is a ServiceFeatureTable, see if it has a service geodatabase
    if (table != null)
    {
        ServiceGeodatabase serviceGdb = table.ServiceGeodatabase;
        if(serviceGdb != null)
        {
            // Load the service geodatabase if necessary
            if (serviceGdb.LoadStatus != LoadStatus.Loaded)
            {
                await serviceGdb.LoadAsync();
            }



    // (continued from above)
            // See if the service geodatabase supports branch versioning
            if (serviceGdb.SupportsBranchVersioning)
            {
                // Get the versions contained in the service geodatabase
                IReadOnlyList versions = await serviceGdb.GetVersionsAsync();

                // Get the info for the current version and read its description
                ServiceVersionInfo thisVersionInfo = versions.First(v => v.Name == serviceGdb.VersionName);
                string versionDesc = thisVersionInfo.Description;



    // (continued from above)
                // Create service version parameters to define a new private version
                var versionParams = new ServiceVersionParameters()
                {
                    Access = VersionAccess.Private,
                    Name = "DesignTwo",
                    Description = "Experimenting with an alternate design"
                };



    // (continued from above)
                // Use the parameters to create a new version in the service geodatabase
                var designTwoVersion = await serviceGdb.CreateVersionAsync(versionParams);

                // Switch the version used in the map to the new one
                await serviceGdb.SwitchVersionAsync(designTwoVersion.Name);
            }
        }



    // Create a new feature and define its geometry and attributes
    Feature feature = table.CreateFeature();
    feature.Geometry = featureLocation;
    feature.SetAttributeValue("CITY", "Chula Vista");

    // Add the new feature to the local table
    await table.AddFeatureAsync(feature);

    // Delete some features
    var cityFeatures = await table.QueryFeaturesAsync(new QueryParameters { WhereClause = "CITY='National City'" });
    await table.DeleteFeaturesAsync(cityFeatures);



    // See which tables are from the service geodatabase
    IReadOnlyList serviceTables = serviceGdb.ConnectedTables;



    if (serviceGdb.HasLocalEdits())
    {
        // Apply local edits for all connected tables to the service
        await serviceGdb.ApplyEditsAsync();
    }



    // Undo all local edits for the version
    await serviceGeodabase.UndoLocalEditsAsync();



// -- CONTINGENT VALUES --//


    // Store a list of values from the contingent values definition.
    var availableValues = new List<CodedValue>();

    // Get all contingent values defined for a specified field name.
    // The attribute values of the feature determine which contingent values are returned.
    var contingentValuesResult = polesFeatureTable.GetContingentValues(inFeature, "Material");

    // Get contingent values for a specified field group.
    var contingentValuesList = contingentValuesResult.ContingentValuesByFieldGroup["voltage_material"];
    // You can use code like this to get contingent values for all field groups if this field participates in more than one.
    // var contingentValuesList = contingentValuesResult.ContingentValuesAllGroups;

    // Loop through the contingent values and add the coded values to a list.
    foreach(var cv in contingentValuesList)
    {
        var contingentCodedValue = cv as ContingentCodedValue;
        if(contingentCodedValue != null)
        {
            availableValues.Add(contingentCodedValue.CodedValue);
        }
    }



    // Check for ContingentAnyValue (which means any value in the domain is valid).
    var contingentAnyValue = cv as ContingentAnyValue;
    if (contingentAnyValue != null)
    {
        // Add all values from the field's domain.
        var domain = _featureTableCV.GetField(fieldName)?.Domain as CodedValueDomain;
        if (domain != null)
        {
            availableValues.AddRange(domain.CodedValues);
        }
    }



    var contingentRangeValue = cv as ContingentRangeValue;
    if (contingentRangeValue != null)
    {
        (Int16 Min, Int16 Max) rangeTuple = ((Int16)contingentRangeValue.MinValue, (Int16)contingentRangeValue.MaxValue);
    }



    var contingentValueViolations = editFeatureTable.ValidateContingencyConstraints(newFeature);

    // If there are no violations, enable the save button and return.
    if (contingentValueViolations.Count == 0)
    {
        ValidateContingentValuesButton.IsEnabled = false;
        SaveFeatureButton.IsEnabled = true;
        return;
    }

    // Loop through contingency violations and show messages for errors and warnings.
    // Include the name of the field group that had the violation.
    foreach(var violation in contingentValueViolations)
    {
        // Show the appropriate icon: an error (red X) or warning (yellow exclamation).
        MessageBoxImage messageIcon = violation.Type == ContingencyConstraintViolationType.Error ?
                                        MessageBoxImage.Error : MessageBoxImage.Warning;
        MessageBox.Show("Contingency value violation for field group '" + violation.FieldGroup.Name + "'",
                        "Violation",
                        MessageBoxButton.OK,
                        messageIcon);
    }

If the contingent values are from a range domain, you can return the minimum and maximum values for the valid range.

Use dark colors for code blocks
                                                                                                                                                                                                                                                                                 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
// --- Edit ---

private async void AddFeature(MapPoint structureLocation, string type, string cause)
{
    // Create attributes for the feature.
    Dictionary<string, object> attributes = new Dictionary<string, object>();
    attributes.Add("typdamage", type);
    attributes.Add("primcause", cause);

    // Create a new feature from the attributes and the point.
    Feature newFeature = _damagePointsTable.CreateFeature(attributes, structureLocation);

    // Add the feature to the local table.
    await _damagePointsTable.AddFeatureAsync(newFeature);

    // If the feature table is a service feature table then
    // apply edits to its service geodatabase.
    ...
}



private async void UpdateFeature(ArcGISFeature arcgisFeature)
{
    // Change the feature's attribute value.
    arcgisFeature.Attributes["typdamage"] = "Inaccessible";

    // Change the feature's geometry.
    MapPoint location = arcgisFeature.Geometry as MapPoint;
    MapPoint newLocation = new MapPoint(location.X, location.Y + 50000);
    arcgisFeature.Geometry = newLocation;

    // Update the feature on the local table.
    await _damagePointsTable.UpdateFeatureAsync(f);

    // If the feature table is a service feature table then
    // apply edits to its service geodatabase.
    ...
}



private async void DeleteSelectedFeatures(FeatureLayer damageLayer)
{
    // Get all selected features in the layer.
    FeatureQueryResult selectedFeatures = await damageLayer.GetSelectedFeaturesAsync();

    // Delete the selected features.
    await _damagePointsTable.DeleteFeaturesAsync(selectedFeatures);

    // If the feature table is a service feature table then
    // apply edits to its service geodatabase.
    ...
}



// If the feature table is a service feature table, send these edits
// to the online service by applying them to its service geodatabase.
EditResult editResults = await table.ServiceGeodatabase.ApplyEditsAsync();


// --- Query ---


// Build a buffer (polygon) around a click point
var buffer = GeometryEngine.Buffer(queryPoint, 5000);

// Use the buffer to define the geometry for a query
var query = new QueryParameters();
query.Geometry = buffer;
query.SpatialRelationship = SpatialRelationship.Contains;

// Select features in a feature layer using the query
await damageLayer.SelectFeaturesAsync(query, Esri.ArcGISRuntime.Mapping.SelectionMode.New);



// TODO:



// TODO:



// TODO:



var layer = MyMapView.Map.OperationalLayers[0];
var pixelTolerance = 20;
var returnPopupsOnly = false;
var maxResults = 5;

// identify a layer using MapView, passing in the layer, the tap point, tolerance, types to return, and max results
IdentifyLayerResult idResults = await MyMapView.IdentifyLayerAsync(layer, tapScreenPoint, pixelTolerance, returnPopupsOnly, maxResults);

// get the layer identified and cast it to FeatureLayer
FeatureLayer idLayer = idResults.LayerContent as FeatureLayer;

// iterate each identified GeoElement in the results
foreach (GeoElement idElement in idResults.GeoElements)
{
    // cast the result GeoElement to Feature
    Feature idFeature = idElement as Feature;

    // select this feature in the feature layer
    idLayer.SelectFeature(idFeature);
}


// -- BRANCH VERSIONING --//


    // Get the feature table from a feature layer and cast it to ServiceFeatureTable
    // (if the table is not a ServiceFeatureTable, it will be null)
    ServiceFeatureTable table = layer.FeatureTable as ServiceFeatureTable;



    // If the feature table is a ServiceFeatureTable, see if it has a service geodatabase
    if (table != null)
    {
        ServiceGeodatabase serviceGdb = table.ServiceGeodatabase;
        if(serviceGdb != null)
        {
            // Load the service geodatabase if necessary
            if (serviceGdb.LoadStatus != LoadStatus.Loaded)
            {
                await serviceGdb.LoadAsync();
            }



    // (continued from above)
            // See if the service geodatabase supports branch versioning
            if (serviceGdb.SupportsBranchVersioning)
            {
                // Get the versions contained in the service geodatabase
                IReadOnlyList versions = await serviceGdb.GetVersionsAsync();

                // Get the info for the current version and read its description
                ServiceVersionInfo thisVersionInfo = versions.First(v => v.Name == serviceGdb.VersionName);
                string versionDesc = thisVersionInfo.Description;



    // (continued from above)
                // Create service version parameters to define a new private version
                var versionParams = new ServiceVersionParameters()
                {
                    Access = VersionAccess.Private,
                    Name = "DesignTwo",
                    Description = "Experimenting with an alternate design"
                };



    // (continued from above)
                // Use the parameters to create a new version in the service geodatabase
                var designTwoVersion = await serviceGdb.CreateVersionAsync(versionParams);

                // Switch the version used in the map to the new one
                await serviceGdb.SwitchVersionAsync(designTwoVersion.Name);
            }
        }



    // Create a new feature and define its geometry and attributes
    Feature feature = table.CreateFeature();
    feature.Geometry = featureLocation;
    feature.SetAttributeValue("CITY", "Chula Vista");

    // Add the new feature to the local table
    await table.AddFeatureAsync(feature);

    // Delete some features
    var cityFeatures = await table.QueryFeaturesAsync(new QueryParameters { WhereClause = "CITY='National City'" });
    await table.DeleteFeaturesAsync(cityFeatures);



    // See which tables are from the service geodatabase
    IReadOnlyList serviceTables = serviceGdb.ConnectedTables;



    if (serviceGdb.HasLocalEdits())
    {
        // Apply local edits for all connected tables to the service
        await serviceGdb.ApplyEditsAsync();
    }



    // Undo all local edits for the version
    await serviceGeodabase.UndoLocalEditsAsync();



// -- CONTINGENT VALUES --//


    // Store a list of values from the contingent values definition.
    var availableValues = new List<CodedValue>();

    // Get all contingent values defined for a specified field name.
    // The attribute values of the feature determine which contingent values are returned.
    var contingentValuesResult = polesFeatureTable.GetContingentValues(inFeature, "Material");

    // Get contingent values for a specified field group.
    var contingentValuesList = contingentValuesResult.ContingentValuesByFieldGroup["voltage_material"];
    // You can use code like this to get contingent values for all field groups if this field participates in more than one.
    // var contingentValuesList = contingentValuesResult.ContingentValuesAllGroups;

    // Loop through the contingent values and add the coded values to a list.
    foreach(var cv in contingentValuesList)
    {
        var contingentCodedValue = cv as ContingentCodedValue;
        if(contingentCodedValue != null)
        {
            availableValues.Add(contingentCodedValue.CodedValue);
        }
    }



    // Check for ContingentAnyValue (which means any value in the domain is valid).
    var contingentAnyValue = cv as ContingentAnyValue;
    if (contingentAnyValue != null)
    {
        // Add all values from the field's domain.
        var domain = _featureTableCV.GetField(fieldName)?.Domain as CodedValueDomain;
        if (domain != null)
        {
            availableValues.AddRange(domain.CodedValues);
        }
    }



    var contingentRangeValue = cv as ContingentRangeValue;
    if (contingentRangeValue != null)
    {
        (Int16 Min, Int16 Max) rangeTuple = ((Int16)contingentRangeValue.MinValue, (Int16)contingentRangeValue.MaxValue);
    }



    var contingentValueViolations = editFeatureTable.ValidateContingencyConstraints(newFeature);

    // If there are no violations, enable the save button and return.
    if (contingentValueViolations.Count == 0)
    {
        ValidateContingentValuesButton.IsEnabled = false;
        SaveFeatureButton.IsEnabled = true;
        return;
    }

    // Loop through contingency violations and show messages for errors and warnings.
    // Include the name of the field group that had the violation.
    foreach(var violation in contingentValueViolations)
    {
        // Show the appropriate icon: an error (red X) or warning (yellow exclamation).
        MessageBoxImage messageIcon = violation.Type == ContingencyConstraintViolationType.Error ?
                                        MessageBoxImage.Error : MessageBoxImage.Warning;
        MessageBox.Show("Contingency value violation for field group '" + violation.FieldGroup.Name + "'",
                        "Violation",
                        MessageBoxButton.OK,
                        messageIcon);
    }

If a ContingentAnyValue is defined for the field, you can provide all values from the field's domain as valid edit choices.

Use dark colors for code blocks
                                                                                                                                                                                                                                                                                 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
// --- Edit ---

private async void AddFeature(MapPoint structureLocation, string type, string cause)
{
    // Create attributes for the feature.
    Dictionary<string, object> attributes = new Dictionary<string, object>();
    attributes.Add("typdamage", type);
    attributes.Add("primcause", cause);

    // Create a new feature from the attributes and the point.
    Feature newFeature = _damagePointsTable.CreateFeature(attributes, structureLocation);

    // Add the feature to the local table.
    await _damagePointsTable.AddFeatureAsync(newFeature);

    // If the feature table is a service feature table then
    // apply edits to its service geodatabase.
    ...
}



private async void UpdateFeature(ArcGISFeature arcgisFeature)
{
    // Change the feature's attribute value.
    arcgisFeature.Attributes["typdamage"] = "Inaccessible";

    // Change the feature's geometry.
    MapPoint location = arcgisFeature.Geometry as MapPoint;
    MapPoint newLocation = new MapPoint(location.X, location.Y + 50000);
    arcgisFeature.Geometry = newLocation;

    // Update the feature on the local table.
    await _damagePointsTable.UpdateFeatureAsync(f);

    // If the feature table is a service feature table then
    // apply edits to its service geodatabase.
    ...
}



private async void DeleteSelectedFeatures(FeatureLayer damageLayer)
{
    // Get all selected features in the layer.
    FeatureQueryResult selectedFeatures = await damageLayer.GetSelectedFeaturesAsync();

    // Delete the selected features.
    await _damagePointsTable.DeleteFeaturesAsync(selectedFeatures);

    // If the feature table is a service feature table then
    // apply edits to its service geodatabase.
    ...
}



// If the feature table is a service feature table, send these edits
// to the online service by applying them to its service geodatabase.
EditResult editResults = await table.ServiceGeodatabase.ApplyEditsAsync();


// --- Query ---


// Build a buffer (polygon) around a click point
var buffer = GeometryEngine.Buffer(queryPoint, 5000);

// Use the buffer to define the geometry for a query
var query = new QueryParameters();
query.Geometry = buffer;
query.SpatialRelationship = SpatialRelationship.Contains;

// Select features in a feature layer using the query
await damageLayer.SelectFeaturesAsync(query, Esri.ArcGISRuntime.Mapping.SelectionMode.New);



// TODO:



// TODO:



// TODO:



var layer = MyMapView.Map.OperationalLayers[0];
var pixelTolerance = 20;
var returnPopupsOnly = false;
var maxResults = 5;

// identify a layer using MapView, passing in the layer, the tap point, tolerance, types to return, and max results
IdentifyLayerResult idResults = await MyMapView.IdentifyLayerAsync(layer, tapScreenPoint, pixelTolerance, returnPopupsOnly, maxResults);

// get the layer identified and cast it to FeatureLayer
FeatureLayer idLayer = idResults.LayerContent as FeatureLayer;

// iterate each identified GeoElement in the results
foreach (GeoElement idElement in idResults.GeoElements)
{
    // cast the result GeoElement to Feature
    Feature idFeature = idElement as Feature;

    // select this feature in the feature layer
    idLayer.SelectFeature(idFeature);
}


// -- BRANCH VERSIONING --//


    // Get the feature table from a feature layer and cast it to ServiceFeatureTable
    // (if the table is not a ServiceFeatureTable, it will be null)
    ServiceFeatureTable table = layer.FeatureTable as ServiceFeatureTable;



    // If the feature table is a ServiceFeatureTable, see if it has a service geodatabase
    if (table != null)
    {
        ServiceGeodatabase serviceGdb = table.ServiceGeodatabase;
        if(serviceGdb != null)
        {
            // Load the service geodatabase if necessary
            if (serviceGdb.LoadStatus != LoadStatus.Loaded)
            {
                await serviceGdb.LoadAsync();
            }



    // (continued from above)
            // See if the service geodatabase supports branch versioning
            if (serviceGdb.SupportsBranchVersioning)
            {
                // Get the versions contained in the service geodatabase
                IReadOnlyList versions = await serviceGdb.GetVersionsAsync();

                // Get the info for the current version and read its description
                ServiceVersionInfo thisVersionInfo = versions.First(v => v.Name == serviceGdb.VersionName);
                string versionDesc = thisVersionInfo.Description;



    // (continued from above)
                // Create service version parameters to define a new private version
                var versionParams = new ServiceVersionParameters()
                {
                    Access = VersionAccess.Private,
                    Name = "DesignTwo",
                    Description = "Experimenting with an alternate design"
                };



    // (continued from above)
                // Use the parameters to create a new version in the service geodatabase
                var designTwoVersion = await serviceGdb.CreateVersionAsync(versionParams);

                // Switch the version used in the map to the new one
                await serviceGdb.SwitchVersionAsync(designTwoVersion.Name);
            }
        }



    // Create a new feature and define its geometry and attributes
    Feature feature = table.CreateFeature();
    feature.Geometry = featureLocation;
    feature.SetAttributeValue("CITY", "Chula Vista");

    // Add the new feature to the local table
    await table.AddFeatureAsync(feature);

    // Delete some features
    var cityFeatures = await table.QueryFeaturesAsync(new QueryParameters { WhereClause = "CITY='National City'" });
    await table.DeleteFeaturesAsync(cityFeatures);



    // See which tables are from the service geodatabase
    IReadOnlyList serviceTables = serviceGdb.ConnectedTables;



    if (serviceGdb.HasLocalEdits())
    {
        // Apply local edits for all connected tables to the service
        await serviceGdb.ApplyEditsAsync();
    }



    // Undo all local edits for the version
    await serviceGeodabase.UndoLocalEditsAsync();



// -- CONTINGENT VALUES --//


    // Store a list of values from the contingent values definition.
    var availableValues = new List<CodedValue>();

    // Get all contingent values defined for a specified field name.
    // The attribute values of the feature determine which contingent values are returned.
    var contingentValuesResult = polesFeatureTable.GetContingentValues(inFeature, "Material");

    // Get contingent values for a specified field group.
    var contingentValuesList = contingentValuesResult.ContingentValuesByFieldGroup["voltage_material"];
    // You can use code like this to get contingent values for all field groups if this field participates in more than one.
    // var contingentValuesList = contingentValuesResult.ContingentValuesAllGroups;

    // Loop through the contingent values and add the coded values to a list.
    foreach(var cv in contingentValuesList)
    {
        var contingentCodedValue = cv as ContingentCodedValue;
        if(contingentCodedValue != null)
        {
            availableValues.Add(contingentCodedValue.CodedValue);
        }
    }



    // Check for ContingentAnyValue (which means any value in the domain is valid).
    var contingentAnyValue = cv as ContingentAnyValue;
    if (contingentAnyValue != null)
    {
        // Add all values from the field's domain.
        var domain = _featureTableCV.GetField(fieldName)?.Domain as CodedValueDomain;
        if (domain != null)
        {
            availableValues.AddRange(domain.CodedValues);
        }
    }



    var contingentRangeValue = cv as ContingentRangeValue;
    if (contingentRangeValue != null)
    {
        (Int16 Min, Int16 Max) rangeTuple = ((Int16)contingentRangeValue.MinValue, (Int16)contingentRangeValue.MaxValue);
    }



    var contingentValueViolations = editFeatureTable.ValidateContingencyConstraints(newFeature);

    // If there are no violations, enable the save button and return.
    if (contingentValueViolations.Count == 0)
    {
        ValidateContingentValuesButton.IsEnabled = false;
        SaveFeatureButton.IsEnabled = true;
        return;
    }

    // Loop through contingency violations and show messages for errors and warnings.
    // Include the name of the field group that had the violation.
    foreach(var violation in contingentValueViolations)
    {
        // Show the appropriate icon: an error (red X) or warning (yellow exclamation).
        MessageBoxImage messageIcon = violation.Type == ContingencyConstraintViolationType.Error ?
                                        MessageBoxImage.Error : MessageBoxImage.Warning;
        MessageBox.Show("Contingency value violation for field group '" + violation.FieldGroup.Name + "'",
                        "Violation",
                        MessageBoxButton.OK,
                        messageIcon);
    }

Validate edits against contingent values

To see if a feature's attribute values conform to the defined contingent values, call the ArcGISFeatureTable.ValidateContingencyConstraints() helper method and pass a feature. The method returns a collection of ContingencyConstraintViolation that you can use to enforce edit restrictions or provide warnings to the user.

Each contingency constraint violation will indicate if it is a warning or an error, and which field group contained the violated contingent value. A violation is considered an error if the field group is marked as restrictive. A restrictive field group means that edits to any of the participating fields should conform to previously defined contingent values. If a field group is not restrictive, then a violation alert is considered a warning.

Use dark colors for code blocks
                                                                                                                                                                                                                                                                                 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
// --- Edit ---

private async void AddFeature(MapPoint structureLocation, string type, string cause)
{
    // Create attributes for the feature.
    Dictionary<string, object> attributes = new Dictionary<string, object>();
    attributes.Add("typdamage", type);
    attributes.Add("primcause", cause);

    // Create a new feature from the attributes and the point.
    Feature newFeature = _damagePointsTable.CreateFeature(attributes, structureLocation);

    // Add the feature to the local table.
    await _damagePointsTable.AddFeatureAsync(newFeature);

    // If the feature table is a service feature table then
    // apply edits to its service geodatabase.
    ...
}



private async void UpdateFeature(ArcGISFeature arcgisFeature)
{
    // Change the feature's attribute value.
    arcgisFeature.Attributes["typdamage"] = "Inaccessible";

    // Change the feature's geometry.
    MapPoint location = arcgisFeature.Geometry as MapPoint;
    MapPoint newLocation = new MapPoint(location.X, location.Y + 50000);
    arcgisFeature.Geometry = newLocation;

    // Update the feature on the local table.
    await _damagePointsTable.UpdateFeatureAsync(f);

    // If the feature table is a service feature table then
    // apply edits to its service geodatabase.
    ...
}



private async void DeleteSelectedFeatures(FeatureLayer damageLayer)
{
    // Get all selected features in the layer.
    FeatureQueryResult selectedFeatures = await damageLayer.GetSelectedFeaturesAsync();

    // Delete the selected features.
    await _damagePointsTable.DeleteFeaturesAsync(selectedFeatures);

    // If the feature table is a service feature table then
    // apply edits to its service geodatabase.
    ...
}



// If the feature table is a service feature table, send these edits
// to the online service by applying them to its service geodatabase.
EditResult editResults = await table.ServiceGeodatabase.ApplyEditsAsync();


// --- Query ---


// Build a buffer (polygon) around a click point
var buffer = GeometryEngine.Buffer(queryPoint, 5000);

// Use the buffer to define the geometry for a query
var query = new QueryParameters();
query.Geometry = buffer;
query.SpatialRelationship = SpatialRelationship.Contains;

// Select features in a feature layer using the query
await damageLayer.SelectFeaturesAsync(query, Esri.ArcGISRuntime.Mapping.SelectionMode.New);



// TODO:



// TODO:



// TODO:



var layer = MyMapView.Map.OperationalLayers[0];
var pixelTolerance = 20;
var returnPopupsOnly = false;
var maxResults = 5;

// identify a layer using MapView, passing in the layer, the tap point, tolerance, types to return, and max results
IdentifyLayerResult idResults = await MyMapView.IdentifyLayerAsync(layer, tapScreenPoint, pixelTolerance, returnPopupsOnly, maxResults);

// get the layer identified and cast it to FeatureLayer
FeatureLayer idLayer = idResults.LayerContent as FeatureLayer;

// iterate each identified GeoElement in the results
foreach (GeoElement idElement in idResults.GeoElements)
{
    // cast the result GeoElement to Feature
    Feature idFeature = idElement as Feature;

    // select this feature in the feature layer
    idLayer.SelectFeature(idFeature);
}


// -- BRANCH VERSIONING --//


    // Get the feature table from a feature layer and cast it to ServiceFeatureTable
    // (if the table is not a ServiceFeatureTable, it will be null)
    ServiceFeatureTable table = layer.FeatureTable as ServiceFeatureTable;



    // If the feature table is a ServiceFeatureTable, see if it has a service geodatabase
    if (table != null)
    {
        ServiceGeodatabase serviceGdb = table.ServiceGeodatabase;
        if(serviceGdb != null)
        {
            // Load the service geodatabase if necessary
            if (serviceGdb.LoadStatus != LoadStatus.Loaded)
            {
                await serviceGdb.LoadAsync();
            }



    // (continued from above)
            // See if the service geodatabase supports branch versioning
            if (serviceGdb.SupportsBranchVersioning)
            {
                // Get the versions contained in the service geodatabase
                IReadOnlyList versions = await serviceGdb.GetVersionsAsync();

                // Get the info for the current version and read its description
                ServiceVersionInfo thisVersionInfo = versions.First(v => v.Name == serviceGdb.VersionName);
                string versionDesc = thisVersionInfo.Description;



    // (continued from above)
                // Create service version parameters to define a new private version
                var versionParams = new ServiceVersionParameters()
                {
                    Access = VersionAccess.Private,
                    Name = "DesignTwo",
                    Description = "Experimenting with an alternate design"
                };



    // (continued from above)
                // Use the parameters to create a new version in the service geodatabase
                var designTwoVersion = await serviceGdb.CreateVersionAsync(versionParams);

                // Switch the version used in the map to the new one
                await serviceGdb.SwitchVersionAsync(designTwoVersion.Name);
            }
        }



    // Create a new feature and define its geometry and attributes
    Feature feature = table.CreateFeature();
    feature.Geometry = featureLocation;
    feature.SetAttributeValue("CITY", "Chula Vista");

    // Add the new feature to the local table
    await table.AddFeatureAsync(feature);

    // Delete some features
    var cityFeatures = await table.QueryFeaturesAsync(new QueryParameters { WhereClause = "CITY='National City'" });
    await table.DeleteFeaturesAsync(cityFeatures);



    // See which tables are from the service geodatabase
    IReadOnlyList serviceTables = serviceGdb.ConnectedTables;



    if (serviceGdb.HasLocalEdits())
    {
        // Apply local edits for all connected tables to the service
        await serviceGdb.ApplyEditsAsync();
    }



    // Undo all local edits for the version
    await serviceGeodabase.UndoLocalEditsAsync();



// -- CONTINGENT VALUES --//


    // Store a list of values from the contingent values definition.
    var availableValues = new List<CodedValue>();

    // Get all contingent values defined for a specified field name.
    // The attribute values of the feature determine which contingent values are returned.
    var contingentValuesResult = polesFeatureTable.GetContingentValues(inFeature, "Material");

    // Get contingent values for a specified field group.
    var contingentValuesList = contingentValuesResult.ContingentValuesByFieldGroup["voltage_material"];
    // You can use code like this to get contingent values for all field groups if this field participates in more than one.
    // var contingentValuesList = contingentValuesResult.ContingentValuesAllGroups;

    // Loop through the contingent values and add the coded values to a list.
    foreach(var cv in contingentValuesList)
    {
        var contingentCodedValue = cv as ContingentCodedValue;
        if(contingentCodedValue != null)
        {
            availableValues.Add(contingentCodedValue.CodedValue);
        }
    }



    // Check for ContingentAnyValue (which means any value in the domain is valid).
    var contingentAnyValue = cv as ContingentAnyValue;
    if (contingentAnyValue != null)
    {
        // Add all values from the field's domain.
        var domain = _featureTableCV.GetField(fieldName)?.Domain as CodedValueDomain;
        if (domain != null)
        {
            availableValues.AddRange(domain.CodedValues);
        }
    }



    var contingentRangeValue = cv as ContingentRangeValue;
    if (contingentRangeValue != null)
    {
        (Int16 Min, Int16 Max) rangeTuple = ((Int16)contingentRangeValue.MinValue, (Int16)contingentRangeValue.MaxValue);
    }



    var contingentValueViolations = editFeatureTable.ValidateContingencyConstraints(newFeature);

    // If there are no violations, enable the save button and return.
    if (contingentValueViolations.Count == 0)
    {
        ValidateContingentValuesButton.IsEnabled = false;
        SaveFeatureButton.IsEnabled = true;
        return;
    }

    // Loop through contingency violations and show messages for errors and warnings.
    // Include the name of the field group that had the violation.
    foreach(var violation in contingentValueViolations)
    {
        // Show the appropriate icon: an error (red X) or warning (yellow exclamation).
        MessageBoxImage messageIcon = violation.Type == ContingencyConstraintViolationType.Error ?
                                        MessageBoxImage.Error : MessageBoxImage.Warning;
        MessageBox.Show("Contingency value violation for field group '" + violation.FieldGroup.Name + "'",
                        "Violation",
                        MessageBoxButton.OK,
                        messageIcon);
    }

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.