Common Custom EditorTask
Common_CustomEditorTask_CSharp\CustomEditorTask_CSharp\CustomSnappingPanel.cs
// Copyright 2010 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.
// 

namespace CustomEditorTask_CSharp
{
    public class CustomSnappingPanel : ESRI.ArcGIS.ADF.ArcGISServer.Editor.EditorPanel
    {
        #region Instance Variable Declarations

        internal const double DEFAULT_SNAP_TOL_MAPUNITS = 50.0;
        private System.Web.UI.WebControls.TableCell m_toleranceTableCell = null;

        #endregion

        #region Constructor

        // Implement a constructor to have the custom snapping panel not be expanded by default
        public CustomSnappingPanel(ESRI.ArcGIS.ADF.ArcGISServer.Editor.EditorTask editorTask)
            : base("Snapping Panel", editorTask, "customSnappingPanel")
        {
            this.Expanded = false;
        }

        #endregion

        #region WebControl Life Cycle Event Overrides

        protected override void OnInit(System.EventArgs eventArgs)
        {
            base.OnInit(eventArgs);

            // Make sure the custom editor task uses map units for snapping and the editor's map is not
            // null before wiring the scale changed event
            if (this.CustomEditorTaskInstance.UseMapUnitsForSnapping && this.ParentEditor.Map != null)
            {
                // Change snap tolerance when map scale changes, if using map units to define tolerance.
                this.ParentEditor.Map.ScaleChanged += 
                    new ESRI.ArcGIS.ADF.Web.UI.WebControls.MapScaleChangeEventHandler(Map_ScaleChanged);
            }
        }

        protected override void OnPreRender(System.EventArgs eventArgs)
        {
            base.OnPreRender(eventArgs);

            // Convert snap tolerance from map units to pixels when rendered, if necessary.
            if (this.CustomEditorTaskInstance.UseMapUnitsForSnapping)
                this.CustomEditorTaskInstance.SnapTolerance = ConvertSnapToleranceMapUnitsToPixels(
                    this.ParentEditor.Map, this.CustomEditorTaskInstance.SnapToleranceMapUnits);

            // If Width not set, set it.
            if (Width == System.Web.UI.WebControls.Unit.Empty)
                Width = new System.Web.UI.WebControls.Unit(300, 
                    System.Web.UI.WebControls.UnitType.Pixel);
        }

        protected override void CreateChildControls()
        {
            base.CreateChildControls();

            if (this.DesignMode)
                return;

            // Make sure the editor has a map resource
            if (ParentEditor.MapResource == null)
                return;

            // Create table to store custom snapping panel's interface
            System.Web.UI.WebControls.Table table = new System.Web.UI.WebControls.Table();

            // Create table row to hold the snap tolerance label
            System.Web.UI.WebControls.TableRow tableRow = new System.Web.UI.WebControls.TableRow();

            // Create table cell and label to hold the static part of the tolerance label
            System.Web.UI.WebControls.TableCell tableCell = new System.Web.UI.WebControls.TableCell();
            tableCell.Text = "Tolerance";

            tableCell.Attributes.Add("class", "edSettingTD");

            // Add the table cell to the row
            tableRow.Controls.Add(tableCell);

            // Create a table cell to hold the dynamic part of the label.  This table cell is stored as an 
            // instance variable so it can be easily referenced
            m_toleranceTableCell = new System.Web.UI.WebControls.TableCell();
            m_toleranceTableCell.ID = "customEditorSnapToleranceLabel";
            m_toleranceTableCell.Text = this.Task.SnapTolerance.ToString() + " Pixels";

            // Add the table cell to the row, the row to the table, and the table to the controls collection
            tableRow.Controls.Add(m_toleranceTableCell);
            table.Controls.Add(tableRow);
            Controls.Add(table);
        }

        protected override void RenderContents(System.Web.UI.HtmlTextWriter htmlTextWriter)
        {
            // Update snap tolerance text
            m_toleranceTableCell.Text = this.Task.SnapTolerance.ToString() + " Pixels";
            base.RenderContents(htmlTextWriter);
        }

        #endregion

        #region Web ADF Control Event Handlers

        // When the map scale changes, recalculate the snap tolerance (in pixels) and update the custom snapping
        // panel accordingly
        void Map_ScaleChanged(object sender, ESRI.ArcGIS.ADF.Web.UI.WebControls.ScaleEventArgs scaleEventArgs)
        {
            // Make sure the old scale is valid and the old scale and new scale are distinct
            if (scaleEventArgs.OldScale == System.Double.NaN || scaleEventArgs.OldScale == scaleEventArgs.NewScale)
                return;

            // Only the map scale factor is needed (map units/pixel).
            // Map scale is (map units/pixel * inches/map unit * pixels/inch)
            this.CustomEditorTaskInstance.SnapTolerance = ConvertSnapToleranceMapUnitsToPixels(
                this.ParentEditor.Map, this.CustomEditorTaskInstance.SnapToleranceMapUnits);

            // Change the snap tolerance label in the snapping panel by constructing a JavaScript callback with
            // the code necessary to change the text of the table cell displaying the snap tolerance
            string jsChangeToleranceLabel = string.Format("document.getElementById('{0}').innerHTML = '{1}'", 
                m_toleranceTableCell.ClientID, this.CustomEditorTaskInstance.SnapTolerance + " Pixels");
            ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult changeToleranceLabelCallbackResult =
                ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult.CreateJavaScript(jsChangeToleranceLabel);
            this.ParentEditor.Map.CallbackResults.Add(changeToleranceLabelCallbackResult);

            // Change the radius of the snap tolerance circle.  Use the ADF JavaScript library to get the client-side
            // Editor object, retrieve the snap tip and set the snap radius size in pixels.    
            string jsChangeToleranceRadius = string.Format("$find('{0}').get_snapTip().set_snapRadius({1})",
                this.ParentEditor.ClientID, CustomEditorTaskInstance.SnapTolerance);
            ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult changeToleranceRadiusCallbackResult =
                ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult.CreateJavaScript(jsChangeToleranceRadius);
            this.ParentEditor.Map.CallbackResults.Add(changeToleranceRadiusCallbackResult);
        }

        #endregion

        #region Instance Properties and Methods

        // Provides easy access to the CustomEditorTask and custom snap properties
        protected CustomEditorTask CustomEditorTaskInstance
        {
            get { return (CustomEditorTask)this.ParentEditor.EditorTask; }
        }

        // Convert tolerance in map units to pixels
        internal int ConvertSnapToleranceMapUnitsToPixels(ESRI.ArcGIS.ADF.Web.UI.WebControls.Map adfMap,
            double snapToleranceMapUnits)
        {
            double mapUnitsPerPixel = (adfMap.Extent.Width / adfMap.TilingScheme.TileWidth);
            return (int)System.Math.Round(snapToleranceMapUnits / mapUnitsPerPixel);
        }

        #endregion
    }
}