Common Custom EditorTask
Common_CustomEditorTask_CSharp\CustomEditorTask_CSharp\CustomSnappingPanel.cs
// Copyright 2007 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.Text;
using ESRI.ArcGIS.ADF.ArcGISServer.Editor;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace CustomEditorTask_CSharp
{
    public class CustomSnappingPanel : EditorPanel
    {
        private System.Web.UI.WebControls.HiddenField m_hiddenField;
        internal const double DEFAULT_SNAP_TOL_MAPUNITS = 50.0;

        public CustomSnappingPanel(EditorTask task)
            : base("Snapping Panel", task, "customSnappingPanel")
        {
            this.Expanded = false;
        }

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

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);

            if (CustomEditorTaskInstance.UseMapUnitsForSnapping)
            {
                // 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(EventArgs e)
        {
            base.OnPreRender(e);

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

            // If Width not set, set it.
            if (Width == Unit.Empty)
                Width = new Unit(300, UnitType.Pixel);

            // Check if display_editorSnapTip.js file is registered.  The JavaScript file is included as embedded resource
            // in EditorTask.  Initialize snap radius and snap tip color.   
            if (!Page.ClientScript.IsStartupScriptRegistered("editorSnapRad") && ParentEditor.MapResource != null)
            {
                string jsSnapRadiusColor = string.Format("SetSnapRadius('{0}',{1});defaultSnapTipColor='{2}';", ParentEditor.Map.ClientID, ParentEditor.EditorTask.SnapTolerance, System.Drawing.ColorTranslator.ToHtml(ParentEditor.EditorTask.SnapTipColor));

                // If snap circle is enabled, turn it on.
                if (ParentEditor.EditorTask.ShowSnapCircle)
                    jsSnapRadiusColor += string.Format(";ShowSnapCircle(\"{0}\",true,null);", ParentEditor.Map.ClientID);

                Page.ClientScript.RegisterStartupScript(this.GetType(), "editorSnapRad", jsSnapRadiusColor, true);
            }
        }

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

            // The HTML hidden field tracks the snap tolerance value in the browser.  It required 
            // for EditorTask JavaScript to render the snap circle and snap tips.  It is updated 
            // When map extent changes.
            m_hiddenField = new HiddenField();
            m_hiddenField.ID = "snapTol";
            m_hiddenField.Value = CustomEditorTaskInstance.SnapTolerance.ToString();
            Controls.Add(m_hiddenField);
        }

        protected override void RenderContents(HtmlTextWriter writer)
        {
            if (ParentEditor.MapResource == null)
                return;

            // Hidden field
            m_hiddenField.RenderControl(writer);

            writer.RenderBeginTag(HtmlTextWriterTag.Table);
            writer.RenderBeginTag(HtmlTextWriterTag.Tr);

            // Add text to show snap tolerance in pixels.  Merely informative, not required.  
            writer.AddAttribute(HtmlTextWriterAttribute.Class, "edSettingTD");
            writer.RenderBeginTag(HtmlTextWriterTag.Td);
            writer.Write("Tolerance");
            writer.RenderEndTag(); // td

            System.Web.UI.HtmlControls.HtmlTableCell htmlTableCellToleranceLabel = new System.Web.UI.HtmlControls.HtmlTableCell("td");
            htmlTableCellToleranceLabel.ID = "customEditorSnapToleranceLabel";
            htmlTableCellToleranceLabel.InnerText = Task.SnapTolerance.ToString() + " Pixels";
            htmlTableCellToleranceLabel.RenderControl(writer);

            writer.RenderEndTag(); // tr
            writer.RenderEndTag(); // table
        }

        // If map scale changed, recalculate the snap tolerance in pixels
        void Map_ScaleChanged(object sender, ESRI.ArcGIS.ADF.Web.UI.WebControls.ScaleEventArgs args)
        {
            if (args.OldScale == Double.NaN || args.OldScale == args.NewScale)
                return;

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

            // Change the snap tolerance label in the snapping panel.
            string jsChangeToleranceLabel = string.Format("document.getElementById('{0}').innerHTML = '{1}'", "customEditorSnapToleranceLabel",
                CustomEditorTaskInstance.SnapTolerance + " Pixels");
            this.ParentEditor.Map.CallbackResults.Add(new ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult(null, null, "javascript", jsChangeToleranceLabel));
            // Change the snap tolerance maintained in Web ADF JavaScript.  Adjusts toleranced for the snap radius and snap tips.
            string newCallbackFunctionString = this.CallbackFunctionString.Replace("'", "\\'");
            string jsChangeToleranceInBrowser = string.Format("window.setTimeout('SetSnapTolerance(document.createElement(\"<input value={3} />\"),\"{0}\",\"{1}\",\"{2}\")', 1);",
                snapTolClientID, this.ParentEditor.Map.ClientID, newCallbackFunctionString, CustomEditorTaskInstance.SnapTolerance);
            this.ParentEditor.Map.CallbackResults.Add(new ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult(null, null, "javascript", jsChangeToleranceInBrowser));
        }

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