Layer Attributes
LayerAttributesForm.cs
// Copyright 2011 ESRI
// 
// All rights reserved under the copyright laws of the United States
// and applicable international laws, treaties, and conventions.
// 
// You may freely redistribute and use this sample code, with or
// without modification, provided you include the original copyright
// notice and use restrictions.
// 
// See the use restrictions.
// 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Collections;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using ESRI.ArcGISExplorer;
using ESRI.ArcGISExplorer.Application;
using ESRI.ArcGISExplorer.Mapping;
using ESRI.ArcGISExplorer.Geometry;
using ESRI.ArcGISExplorer.Data;

namespace LayerAttributesCS
{
  public partial class LayerAttributesForm : Form
  {
    private TableBindingAdapter _tableAdapter = null;
    private MapDisplay _mapDisplay = ESRI.ArcGISExplorer.Application.Application.ActiveMapDisplay;
    private FeatureLayer _fl = null;
    private string _idColumnName = string.Empty;

    /// <summary>
    /// Initializes a new instance of the LayerAttributesForm class.
    /// </summary>
    /// <param name="fl">A FeatureLayer</param>
    public LayerAttributesForm(FeatureLayer fl)
    {
      InitializeComponent();
      
      _fl = fl;
      _idColumnName = _fl.Table.Columns.ObjectIDColumnName;
      
      //**********************
      //Important code - steps
      //1. Create a new TableBindingAdapter using the Table associated with the specified feature layer.
      //2. Call the Fill method to populate the adapter with data from the Table.
      //3. Set the datasource property on the bindingSource1 component.
      //4. Bind the bindingSource1 component to the dataGridView1 and bindingNavigator1 objects.
      _tableAdapter = new TableBindingAdapter(_fl.Table);
      _tableAdapter.Fill();
      bindingSource1.DataSource = _tableAdapter;
      dataGridView1.DataSource = bindingSource1;
      bindingNavigator1.BindingSource = bindingSource1;
      //***********************
     
      this.Text = String.Format("{0} Attributes", _fl.Name);
      btnZoomTo.ToolTipText = "Zoom to feature";
      btnClearGraphicForRow.ToolTipText = "Clear graphic for feature";
      btnShowGraphicForRow.ToolTipText = "Show graphic for feature";
      btnClearAllGraphicsForTable.ToolTipText = string.Format("Remove all {0} graphics", _fl.Name);

    }

    #region "public properties"
    /// <summary>
    /// Gets the feature layer for which the attribute data is displayed.
    /// </summary>
    /// <value>A FeatureLayer object representing spatial, vector data.</value>
    public FeatureLayer FeatureLayer
    {
      get { return _fl; }
    }
    #endregion

    #region "button implementation"

    /// <summary>
    /// Handles the Click event of the btnZoomTo control. Zooms to the geometry stored in the Shape column
    /// of a particular Row.
    /// </summary>
    private void btnZoomTo_Click(object sender, EventArgs e)
    {
      string idColName = _fl.Table.Columns.ObjectIDColumnName;
      int objectID = (int)dataGridView1.CurrentRow.Cells[idColName].Value;

      Row row = _fl.Table.GetRow(objectID);

      if (row != null)
      {
        Geometry geom = row.Geometry;

        if ((geom != null) && (geom.IsEmpty == false))
        {
          //Zoom if there is a valid geometry that is not empty.
          _mapDisplay.ZoomTo(geom);
        }
      }
    }

    /// <summary>
    /// Handles the Click event of the btnShowGraphicForRow control. Creates a graphic from the geometry stored 
    /// in the Shape column of a particular Row and adds it to the map.
    /// </summary>
    /// <remarks>Note that graphics are temporary - they will not be saved in the Map Document (.nmf) and
    /// additionally they will be removed when the LayerAttributesForm is closed.</remarks>
    private void btnShowGraphicForRow_Click(object sender, EventArgs e)
    {
      string idColName = _fl.Table.Columns.ObjectIDColumnName;
      int objectID = (int)dataGridView1.CurrentRow.Cells[idColName].Value;

      Row row = _fl.Table.GetRow(objectID);
      //Get the Geometry for the selected Row
      Geometry geometry = row.Geometry;

      Symbol sym;
      //Create a new symbol for the Point, Line and Polygon geometry types. Note that other types are not supported.
      switch (geometry.GeometryType)
      {
        case GeometryType.Point:
          sym = Symbol.Marker.Flag.Red;
          break;
        case GeometryType.Polygon:
          sym = Symbol.Fill.Outline.Blue;
          break;
        case GeometryType.Polyline:
          sym = Symbol.Line.Solid.Green;
          break;
        //currently only create symbols for points, lines and polygons
        default:
          sym = null;
          break;
      }

      if (sym != null)
      {
        //Create a new graphic
        Graphic gr = new Graphic(geometry, sym);

        //"Tag" the graphic so that it can be found later and removed
        FeatureLayerAndObjectId identifier = new FeatureLayerAndObjectId();
        identifier.FeatureLayer = _fl;
        identifier.ObjectId = objectID;
        gr.Tag = identifier;

        //add the graphic to the GraphicsCollection
        _mapDisplay.Graphics.Add(gr);
        //update the buttons enabled status if required
        SetButtonEnabledState();
      }
    }


    /// <summary>
    /// Handles the Click event of the btnClearGraphicForRow control. Removes a graphic for a particular Row
    /// </summary>
    private void btnClearGraphicForRow_Click(object sender, EventArgs e)
    {
      int clickedOID = (int)dataGridView1.CurrentRow.Cells[_idColumnName].Value;
      Graphic graphicToDelete = null;

      foreach (Graphic graphic in _mapDisplay.Graphics)
      {
        object graphicTag = graphic.Tag;

        if ((graphicTag != null) && (graphicTag is FeatureLayerAndObjectId))
        {
          FeatureLayerAndObjectId customTag = graphicTag as FeatureLayerAndObjectId;

          FeatureLayer foundLayer = customTag.FeatureLayer;
          int foundOID = customTag.ObjectId;

          if ((foundLayer == _fl) && (foundOID == clickedOID))
          {
            graphicToDelete = graphic;
            break;
          }
        }
      }

      //if a graphic was found in the Graphics collection for this Row then remove it
      if (graphicToDelete != null)
      {
        _mapDisplay.Graphics.Remove(graphicToDelete);
      }

      //update the buttons enabled status if required
      SetButtonEnabledState();
    }

    /// <summary>
    /// Handles the Click event of the btnClearAllGraphicsForTable control. Clears all graphics which
    /// have been added to the map for this feature layer
    /// </summary>
    private void btnClearAllGraphicsForTable_Click(object sender, EventArgs e)
    {
      List<Graphic> graphicsToDelete = new List<Graphic>();

      foreach (Graphic graphic in _mapDisplay.Graphics)
      {
        object graphicTag = graphic.Tag;

        if ((graphicTag != null) && (graphicTag is FeatureLayerAndObjectId))
        {
          FeatureLayerAndObjectId customTag = graphicTag as FeatureLayerAndObjectId;

          FeatureLayer foundLayer = customTag.FeatureLayer;

          if (foundLayer == _fl)
          {
            graphicsToDelete.Add(graphic);
          }
        }
      }

      //Delete any graphics associated with this feature layer
      foreach (Graphic featureGraphic in graphicsToDelete)
      {
        _mapDisplay.Graphics.Remove(featureGraphic);
      }

      //update the buttons enabled status if required
      SetButtonEnabledState();
    }
    #endregion

    #region "other event handlers"

    /// <summary>
    /// Handles the FormClosing event and ensures that all graphics are removed for the 
    /// feature layer when the form is closed.
    /// </summary>
    private void AttributesForm_FormClosing(object sender, FormClosingEventArgs e)
    {
      btnClearAllGraphicsForTable_Click(null, null);
    }

    /// <summary>
    /// Handles the SelectionChanged event within dataGridView1 control by checking to see if the 
    /// button enabled state should be changed.
    /// </summary>
    private void dataGridView1_SelectionChanged(object sender, EventArgs e)
    {
      SetButtonEnabledState();
    }
    #endregion

    #region "private methods"

    /// <summary>
    /// Determines whether a graphic has already been added to the Map for the selected Row of data.
    /// </summary>
    /// <returns>true if a graphic is found, otherwise false.</returns>
    private bool IsGraphicShownForRow()
    {
      int clickedOID = (int)dataGridView1.CurrentRow.Cells[_idColumnName].Value;
      bool foundGraphicForRow = false;

      foreach (Graphic graphic in _mapDisplay.Graphics)
      {
        object graphicTag = graphic.Tag;

        if ((graphicTag != null) && (graphicTag is FeatureLayerAndObjectId))
        {
          FeatureLayerAndObjectId customTag = graphicTag as FeatureLayerAndObjectId;

          FeatureLayer foundLayer = customTag.FeatureLayer;
          int foundOID = customTag.ObjectId;

          if ((foundLayer == _fl) && (foundOID == clickedOID))
          {
            foundGraphicForRow = true;
            break;
          }
        }
      }
      
      return foundGraphicForRow;     
    }

    /// <summary>
    /// Determines whether any graphics have been added to the map for this Table
    /// </summary>
    /// <returns>true if any graphics have been added to the map for this Table, otherwise false</returns>
    private bool HasMapGotGraphicsForLayer()
    {
      bool foundGraphics = false;
 
      foreach (Graphic graphic in _mapDisplay.Graphics)
      {
        object graphicTag = graphic.Tag;

        if ((graphicTag != null) && (graphicTag is FeatureLayerAndObjectId))
        {
          FeatureLayerAndObjectId customTag = graphicTag as FeatureLayerAndObjectId;

          FeatureLayer foundLayer = customTag.FeatureLayer;
          
          if (foundLayer == _fl)
          {
            foundGraphics = true;
            break;
          }
        }
      }
      return foundGraphics;
    }

    /// <summary>
    /// Sets the enabled state for the custom buttons which have been added to the binding navigator
    /// </summary>
    private void SetButtonEnabledState()
    {
      DataGridViewSelectedRowCollection selectedRows = dataGridView1.SelectedRows;

      bool enableAddGraphicBtn = false;
      bool enableRemoveGraphicBtn = false;
      bool enableZoomToBtn = false;

      //only enable the buttons after making necessary checks
      if (selectedRows != null)
      {
        enableZoomToBtn = true;

        bool graphicExistsForRow = IsGraphicShownForRow();
        enableAddGraphicBtn = !graphicExistsForRow;
        enableRemoveGraphicBtn = graphicExistsForRow;

        btnShowGraphicForRow.Enabled = enableAddGraphicBtn;
        btnClearGraphicForRow.Enabled = enableRemoveGraphicBtn;
        btnZoomTo.Enabled = enableZoomToBtn;
      }

      //doesn't matter whether there is a selection
      btnClearAllGraphicsForTable.Enabled = HasMapGotGraphicsForLayer();
    }
    #endregion
  }

  /// <summary>
  /// Helper class used for tagging graphics, allowing then to be easily identified and removed 
  /// </summary>
  public class FeatureLayerAndObjectId
  {
    public int ObjectId { get; set; }
    public FeatureLayer FeatureLayer { get; set; }
  }

}