Customizing CollectFeaturesTask

For data collection and feature inspection, the built-in CollectFeaturesTask provides a set of geometry and attribute collection methods to get fieldwork done. You start with a page where you can pick a feature type to collect data for, followed by another page with options to start geometry collection or attribute collection. For geometry collection, there is a list of geometry collection methods to choose from, and depending on which method is selected, the application will show additional pages to guide you through the geometry collection procedure. Attribute collection is pretty straightforward, allowing you to tap a field (represented by a group) to activate the data entry page. After both geometry and attributes have been collected, you can choose to save and finish (if you don't want to re-collect geometry or edit attributes again). This typically completes a data collection procedure.

The graphic below shows a typical data collection workflow as defined by CollectFeaturesTask:

Notification when feature collection begins/ends

CollectFeaturesTask provides two events that will be raised—CollectionStarted when collection of a new feature begins and CollectionCompleted when collection of a new feature is completed.

As you begin data collection, you start with a page where a feature type can be selected. After you choose a feature type to collect data for, the CollectionStarted event will be fired. You can get the reference to the new feature being collected from the CollectFeaturesTask.Feature property. Similarly, the CollectionCompleted event will be raised either after the collection of the new feature has finished or if the feature collection is canceled.

Adding/Removing geometry collection methods

CollectFeaturesTask provides a set of geometry collection methods commonly used by field data collections (as shown above). However, if your field data collection requires a new geometry collection method, you can do so in the framework. You can simply implement your own geometry collection method and add it to the Geometry Collection page. To add your method to the Geometry Collection page, listen to the CollectFeaturesTask.CreatingGeometryCollectionMethods event, which will be fired when a list of geometry collection methods is being constructed on the Geometry Collection page. Through the ActionItemEventArgs.ActionItems list, you can remove built-in geometry collection methods or add your own methods here.

Customizing finish collection options

Note that you can also customize FinishCollectionOptions. To customize the option list on this page, listen to the CollectFeaturesTask.CreatingFinishCollectionOptions event and add/remove options as needed.

The following code snippet from the CollectFeaturesExtension sample adds a new geometry collection method and a new custom finish option:

using System;
using ESRI.ArcGIS.Mobile.Client;
using ESRI.ArcGIS.Mobile.MapActions;
using System.Windows.Forms;
using ESRI.ArcGIS.Mobile.Client.Controls;
using System.Collections.Generic;
using System.Data;
using ESRI.ArcGIS.Mobile;
using ESRI.ArcGIS.Mobile.Geometries;
using ESRI.ArcGIS.Mobile.MobileServices;
using ESRI.ArcGIS.Mobile.Client.Tasks.CollectFeatures;
using ESRI.ArcGIS.Mobile.Client.GeometryCollectionMethods; 

namespace CustomizationSamples
{
  /// <summary>
  /// 
  /// </summary>
  public class CollectFeaturesExtension : ProjectExtension
  {
    CollectFeaturesTask m_collectFeaturesTask;
    ExtendedListViewItem m_customGeometryMethodLvi;
    ExtendedListViewItem m_customFinishLvi;
    ExtendedListViewItem m_customAvgLvi; 

    ListViewActionItem m_customGeometryMethodActionItem;
    ListViewActionItem m_customFinishActionItem;
    ListViewActionItem m_customAvgActionItem; 

    /// <summary>
    /// Constructor
    /// </summary>
    public CollectFeaturesExtension()
    {
      m_customGeometryMethodLvi = new ExtendedListViewItem("Put in random place");
      m_customGeometryMethodLvi.SecondaryStrings.Add("Put the point in a random spot...");
      m_customGeometryMethodActionItem = new ListViewActionItem("Random", m_customGeometryMethodLvi, RandomGeometryCollection); 

      m_customFinishLvi = new ExtendedListViewItem("Custom Finish List Item");
      m_customFinishLvi.SecondaryStrings.Add("Custom finish list item...");
      m_customFinishActionItem = new ListViewActionItem("CustomFinish", m_customFinishLvi, CustomFinish);

      m_customAvgLvi = new ExtendedListViewItem("Range finder offset");
      m_customAvgLvi.SecondaryStrings.Add("Range finder offset");
      m_customAvgActionItem = new ListViewActionItem("RangeFinderOffset", m_customAvgLvi, RangeFinderOffset);
    } 

    /// <summary>
    /// This method is called by the Project when the Project is initializing.
    /// At this point you are guaranteed that all other Tasks and Extensions
    /// have been instantiated.
    /// </summary>
    protected override void Initialize()
    {
      m_collectFeaturesTask = MobileApplication.Current.Project.Tasks.GetFirstExtensionOfType(typeof(CollectFeaturesTask)) as CollectFeaturesTask;
      if (m_collectFeaturesTask == null)
        return;
      m_collectFeaturesTask.CreatingFinishCollectionOptions += new ActionItemEventHandler<ListViewActionItem>(CreatingFinishCollectionOptions);
      GeometryCollectionMethodPage.CreatingGeometryCollectionMethods += new ActionItemEventHandler<ListViewActionItem>(CreatingGeometryCollectionMethods);
    } 

    /// <summary>
    /// This method is called by the Project when it is Initialized. At this point,
    /// all other Tasks and ProjectExtensions will have been Initialized.
    /// </summary>
    /// <remarks>
    /// Do not change add/remove ProjectExtensions to the Project or Application
    /// during this method.
    /// </remarks>
    protected override void OnOwnerInitialized()
    {
    } 

    private void RandomGeometryCollection()
    {
      RandomGeometryCollectionMethod rgcm = new RandomGeometryCollectionMethod();
      rgcm.StartGeometryCollection(m_collectFeaturesTask.Feature);
    } 

    void CreatingGeometryCollectionMethods(object sender, ActionItemEventArgs<ListViewActionItem> e)
    {
      //e.ActionItems.Clear();
      if (m_collectFeaturesTask.Feature.FeatureLayer.GeometryType == ESRI.ArcGIS.Mobile.Geometries.GeometryType.Point)
      {
        e.ActionItems.Add(m_customGeometryMethodActionItem);
      }
    }

     void CreatingFinishCollectionOptions(object sender, ActionItemEventArgs<ListViewActionItem> e)
   {
      //e.ActionItems.Clear();
      e.ActionItems.Add(m_customFinishActionItem);
    } 

    private void RangeFinderOffset()
    {
      MessageBox.Show("applying range finder offset...");
    } 

    private void CustomFinish()
    {
      MessageBox.Show("You finished.");
      MobileApplication.Current.Transition(MobileApplication.Current.Project.SelectTaskPage);
    } 

    ///<summary>
    /// This method is called by the Project before the Project is closed.
    /// This gives you the opportunity to detach events from application level objects.
    /// </summary>
    protected override void Uninitialize()
    {
      m_collectFeaturesTask.CreatingFinishCollectionOptions -= new ActionItemEventHandler<ListViewActionItem>(CreatingFinishCollectionOptions);
      GeometryCollectionMethodPage.CreatingGeometryCollectionMethods -= new ActionItemEventHandler<ListViewActionItem>(CreatingGeometryCollectionMethods);
    }
  }
} 

  public class RandomGeometryCollectionMethod : GeometryCollectionMethod
  {
    static Random m_random = new Random(Environment.TickCount); 


    /// <summary>
    /// Called when geometry collection should start.
    /// </summary>
    /// <remarks>
    /// This method is called when the geometry collection should start.
    /// Derived classes should override this method. The Feature and Geometry properties
    /// will be filled by this point.
    /// </remarks>
    protected override void OnStartGeometryCollection()
    {
      Envelope env = MobileApplication.Current.Project.SharedMap.GetExtent(); 

      double x = m_random.NextDouble();
      x = x * env.Width;
      x += env.XMin;

      double y = m_random.NextDouble();
      y = y * env.Height;
      y += env.YMin; 

      Coordinate c = new Coordinate(x, y);

      Geometry.InsertCoordinateAfter(c);

      // notify static event that collection is complete
      NotifyCollectionCompleted();
    } 
  } 


9/20/2011