Sunday, June 10, 2012

Linq2ArcObjects basic version

Introduction

Due to lack of time and also because I have no longer ArcGis desktop on my development environment  I made the code public. This library allows the use of Microsoft  Linq to access rows from attribute tables and feature classes.

To-do’s

I did only limited testing on this library, writing some unit tests could help to stabilize the development of future versions.
A more important job to do is the adding of spatial query possibility. Therefor a special keyword like ‘whereSpatial’ must be added to the Linq syntax.  Not a lot of work, you can look how the attribute query is constructed from the query functionality of the ArcObjects library.  To help the parsing, you have to add special attributes like geometry at the class definition for a feature. This will be needed at the table level and also at attribute level to specify which field contains the geometry contents.

Microsoft has a GUI interface for his Linq to SQL implementation. To eliminate the writing of the table classes, a tool written with ArcObjects engine is useful for generating the classes in C# (or VB.NET). Not a hard job for one that has some experience in processing geodatabases. All information needed in the class definitions is available using ArcObjects methods.
Basic knowledge

The code is written in c#, no VB.NET version is available
You need to have knowledge in the use of attributes defined for classes and properties. Attributes are the driving engine within the Linq parsing.

You need to have knowledge of reading and writing of feature classes. The library can be used with every SDE database. I did no check for the use of file GDB , Access database or shape files.
Code access

I used GIT to make the code public, I did not found another solution. As I am new with GIT , I hope all is correctly transferred.
The repository has the name ‘jpenet / Linq2ArcObjects’ and can be found at https://github.com/
 

Have a lot of programming fun,

Johnny Penet

10/6/2012           Lokeren, Belgium

Saturday, June 9, 2012

ARCGIS JavaScript API – BASIC EDITING COMMANDS SECTION 2 – PART V

1.     Introduction

Until now we saw how we can create and update geometries  (points, polylines and polygones) using the edit and draw widgets. Using the save button we transfer the modification to the ArcGIS server which in turn updates the SDE database. Also important is the data entry of attribute data of a feature. I will illustrate how we can use the attribute template widget to create a general attribute editor for features.
The navigation within the tab control and the accordion control inside a tab will be done with the help of custom bindings as defined in the knockoutJS framework. As we illustrated in previous commands, the handling of the GUI components will be kept out of the ArcGIS framework.
2.     Attribute edit

To simplify the attribute editing we can use the attribute inspector of the ArcGIS JavaScript API. This is a dojo widget that covers the full editing of attributes for a feature. Depending on the attribute field type different input editors are activated in the Dojo component.
The attribute inspector is encapsulated in some general edit attribute method added into the GisEditing class.  The only parameter needed for the tool is the list of fields that needs to be updated. In the implementation a general editing application, we called this method with a null value as field list. Using a null value as field list results in adding all attribute fields of the feature. The object ID is always masked out by the attribute inspector. and does not appears on the input form.

editAttributes: function (fieldInfos) {
 try {
  if (currentFeatureLayer == null)
       return;
   currentOperation = "EditAttributes";
   if (fieldInfos == null)
       fieldInfos = [];
   var layerInfos = [{
      'featureLayer': GisOperation.getMap().getLayer(currentFeatureLayer.name),
      'showDeleteButton': false,
      'isEditable': true,
      'fieldInfos': fieldInfos
   }];
   if (attributeInspector == null) {
      var contentHolder = "<div id='" + attributesDiv + "'></div>";
      require(["dojo/dom-construct"], function (domConstruct) {
         domConstruct.place(contentHolder, "attributeDetails", "first");
      });
      attributeInspector = new esri.dijit.AttributeInspector({
        layerInfos: layerInfos
        }, attributesDiv);
      dojo.connect(attributeInspector, "onAttributeChange", function (feature, fieldName,  
          newFieldValue) {
        //store the updates to apply when the save button is clicked
        currentFeatureLayer.getSelectedFeatures()[0].attributes[fieldName] = newFieldValue;
     });
     }
   this.selectFeatures();
 } catch (err) {
     logging.logMessage("E", "editAttributes failed -->" + err.message, "gisEditing");
 }
},

To  include the attribute inspector widget into the web page,  the best implementation I found is using the dom contructor of the dojo library.  I found out that this is the most stable creation of this component into the web page. This result of the display within the tabular control looks like this:
The nice thing is that with the attribute inspector widget , you get a rich input controls which handles the different input data types of the feature.  The ‘onAttributeChange’ event of the attribute inspector is responsible for the update of the modified attributes into the selected feature. The attribute inspector add also support for the usage of attachments. As you can also see, the attribute inspector add multi language support., but as I did with Silverlight I did not add some multi language support. 
3.     Move point

Although we add a separate tool button to move a point, the implementation of the tool is exactly the same as modifying the vertices of a polygon or polyline. In the main view model class the implementation of the edit tools looks like this :
Edit of the vertices:
    this.editExecute = function () {
        editToolbarGeneralViewModel.editCommand(setEditActive);
    };

 Move of a point:
    this.movePointExecute = function () {
        editToolbarGeneralViewModel.editCommand(setEditActive);
    };

 The underlying edit command will handle the different feature types, and in case of a map point you are allow the move of the point with a drag operation.
4.     Save feature

The save action has been split into the three different actions that can be done on a feature layer,  namely create, update and delete. The code below shows that with the current API you can have the full control over editing on feature layers and how the results are save at the ArcGIS server.

saveAll: function () {
  try {
      var updateGraphic;
      if (currentOperation == "EditVertices") {
         var graphicNew = editTool.getCurrentState();
         if (graphicNew.isModified) {
             updateGraphic = currentFeatureLayer.getSelectedFeatures()[0].setGeometry(graphicNew.graphic.geometry);
             currentFeatureLayer.applyEdits(null, [updateGraphic], null, function (addResults, updateResults, deleteResults) {
             var updateCount = updateResults.length;
             }, function (err) {
                 logging.logMessage("E", "saveAll applyEdits failed -->" + err.message, "gisEditing");
             });
         }
         editTool.deactivate();
      }
      else if (currentOperation == "EditAttributes") {
        try {
          attributeInspector.destroy();
          attributeInspector = null;
          updateGraphic = currentFeatureLayer.getSelectedFeatures()[0];
          currentFeatureLayer.applyEdits(null, [updateGraphic], null, function (addResults, updateResults, deleteResults) {
              var updateCount = updateResults.length;
          }, function (err) {
              logging.logMessage("E", "saveAll applyEdits failed -->" + err.message, "gisEditing");
          });
        } catch (err) {
            logging.logMessage("E", "saveAll failed EditAttributes-->" + err.message, "gisEditing");
        }
      }
      else if (currentOperation == "CreateFeature") {
        if (currentGeometry != null) {
           var symbol;
          if (currentFeatureLayer.geometryType == "esriGeometryPolygon") {
               symbol = gisOperation.getSelectionFillSymbol();
          }
          else if (currentFeatureLayer.geometryType == "esriGeometryPolyline") {
               symbol = gisOperation.getSelectionLineSymbol();
          }
          else if (currentFeatureLayer.geometryType == "esriGeometryPoint") {
               symbol = gisOperation.getSelectionMarkerSymbol();
          }
          var addGraphic = new esri.Graphic(currentGeometry, symbol, currentAttributes);
          currentFeatureLayer.applyEdits([addGraphic], null, null, function (addResults, updateResults, deleteResults) {
              var addCount = addResults.length;
              }, function (err) {
                 logging.logMessage("E", "saveAll apply add failed -->" + err.message, "gisEditing");
           });
        }
        gisOperation.getDraw().deactivate();
      }
      else if (currentOperation == "DeleteFeatures") {
        try {
         var deleteFeatures = new Array();
         require(["dojo/_base/array"], function (array) {
           array.forEach(currentFeatureLayer.getSelectedFeatures(), function (feature, ind) {
              deleteFeatures.push(feature);
           });
         });
         currentFeatureLayer.applyEdits(null, null, deleteFeatures, function (addResults, updateResults, deleteResults) {
            var deleteCount = deleteResults.length;
            }, function (err) {
              logging.logMessage("E", "saveAll applyEdits failed -->" + err.message, "gisEditing");
          });
        } catch (err) {
          logging.logMessage("E", "saveAll failed DeleteFeatures -->" + err.message, "gisEditing");
        }
      }
      currentOperation = "";
      currentAttributes = new Array();
      this.clearSelectFeatures();
      gisOperation.getSelectLayer().clear();
   } catch (err) {
       logging.logMessage("E", "saveAll failed -->" + err.message, "gisEditing")
 }
},


In the save there is a lot of asynchronous processing. By hiding this asynchronous functionality, it makes the job easier at the GUI development. It is also important to add extensive error handling to have a trace in case of errors occurred during the save operation.
5.     Undo modifications
As long as you did not a save with the save button, nothing is modified on the ArcGIS server. Simply clear the graphic layer, as it holds the modification or creation. In case of attribute update, destroy the attribute inspector.

6.     Summary

In the edit tools I showed you how you can implement some simple basis editing of feature layers. Editing, updating or delete of feature can be performed in the same way that is done with ArcGIS Desktop. With the attribute inspector you even get a powerful attribute editor. In the future I hope to illustrate how you can create more complex edit tools as already illustrated in the Silverlight ArcGIS framework illustrated in previous documents. The basic idea will be creating basic building blocks of editing tools that can be put together to create more complex edit tools. This approach is not special, probably a lot of you has already built ArcMap extensions with the main purpose to create extended edit tools to simplify the job of GIS editors.
Based on my experience of writing ArcMap extension for enhanced GIS editing, I will later illustrate how some of this more complex editing tools I implemented in the past as ArcMap tools or commands can be written as tools or commands in JavaScript as part of an ArcGIS Application framework.
ESRI inc. did a real good job by putting an ArcGIS API framework in place to encapsulate the REST services for the ArcGIS Server together with the 10.01 editing functionality for feature layers. This gives us as GIS developers an