Common Custom EditorTask
Common_CustomEditorTask_CSharp\CustomEditorTaskWebApp_CSharp\StandardEditorTaskPage.aspx.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.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using ESRI.ArcGIS.Server;
using ESRI.ArcGIS.ADF.ArcGISServer.Editor;

public partial class StandardEditorTaskPage : System.Web.UI.Page, ICallbackEventHandler
{
    // Member variables to manage callbacks in the Web app.  Use to release server context for
    // non-pooled resources.
    public string m_closeOutCallback = "";
    private string m_callbackArg;

    // Add event handlers for out-of-the-box EditorTask during Page Init
    protected void Page_Init(object sender, EventArgs e)
    {
        EditorTask1.EditorPanelsCreated += new ESRI.ArcGIS.ADF.ArcGISServer.Editor.EditorPanelsCreatedEventHandler(EditorTask1_EditorPanelsCreated);
        EditorTask1.ToolsCreated += new ESRI.ArcGIS.ADF.ArcGISServer.Editor.Tools.ToolsCreatedEventHandler(EditorTask1_ToolsCreated);

        EditorTask1.PreAttributeEdit += new PreAttributeEditEventHandler(EditorTask1_PreAttributeEdit);
        EditorTask1.PostAttributeEdit += new PostAttributeEditEventHandler(EditorTask1_PostAttributeEdit);

        EditorTask1.PreCommandExecute += new ESRI.ArcGIS.ADF.ArcGISServer.Editor.Tools.PreCommandExecuteEventHandler(EditorTask1_PreCommandExecute);       
    }


    void EditorTask1_PreCommandExecute(object sender, ESRI.ArcGIS.ADF.ArcGISServer.Editor.Tools.PreCommandExecuteEventArgs e)
    {
        // Cancel the DeleteFeature command if the active edit layer is AddressPoints
        string commandName = e.ServerAction.ToolbarItemInfo.Name;
        string datasetName = e.ServerAction.DataSet.Name;
        if (commandName.Equals("DeleteFeature") && datasetName.Equals("EditParcels.DBO.AddressPoints"))
        {
            e.Cancel = true;
            e.ReturnMessage = "Cannot delete features in " + datasetName;
        }
    }

    void EditorTask1_PreAttributeEdit(object sender, PreAttributeEditEventArgs e)
    {
        // If the an attribute is edited, check the fields of the feature being edited
        // for a field named "UPDATEDBY".  If present, and the current user is authenticated,
        // set the value of the field to the user name.
        int fieldIndex = e.Feature.Table.FindField("UPDATEDBY");

        if (fieldIndex > -1)
        {
            string authenticatedUserName = Context.User.Identity.Name;
            if (!string.IsNullOrEmpty(authenticatedUserName))
                e.Feature.set_Value(fieldIndex, authenticatedUserName);
        }
    }

    void EditorTask1_PostAttributeEdit(object sender, PostAttributeEditEventArgs e)
    {
        // If an attribute edit is unsuccessful, return exception message in a browser alert dialog.
        if (!e.Successful)
            e.ReturnMessage = e.Exception.Message;
    }

    void EditorTask1_EditorPanelsCreated(object sender, ESRI.ArcGIS.ADF.ArcGISServer.Editor.EditorPanelsCreatedEventArgs e)
    {
        // Create instance of new Editor Panel that contains a CreateFeature tool
        CustomCreateFeaturePanel newCreateFeaturePanel = new CustomCreateFeaturePanel(EditorTask1);
        // Insert at the beginning (top) of the panels collection in the Editor
        e.EditorPanels.Insert(0, newCreateFeaturePanel);


        // If using the out-of-the-box EditorTask and CreateFeature tool,
        // the exiting CreateFeaturePanel cannot be removed.   The CreateFeature tool
        // uses the FeatureLabel property on the CreateFeaturePanel returned from Editor.NewFeatureCreator.
        //e.EditorPanels.Remove(editorPanel);
        ESRI.ArcGIS.ADF.ArcGISServer.Editor.EditorPanel editorPanel =
            newCreateFeaturePanel.ParentEditor.NewFeatureCreator;
        editorPanel.Visible = false;
    }

    void EditorTask1_ToolsCreated(object sender, ESRI.ArcGIS.ADF.ArcGISServer.Editor.Tools.ToolsCreatedEventArgs e)
    {
        if (e.Parent == EditorTask1.Editor.ExistingFeatureEditor)
        {
            // The out-of-the-box EditExistingFeaturePanel contains two toolbars: GeometryToolbar1 and GeometryToolbar2
            foreach (ESRI.ArcGIS.ADF.ArcGISServer.Editor.Tools.EditorToolbar editorToolbar in e.Toolbars)
            {
                if (editorToolbar.ID == "GeometryToolbar1")
                {
                    // Add custom Clip tool to the first toolbar in the EditExistingFeaturePanel
                    ESRI.ArcGIS.ADF.ArcGISServer.Editor.Tools.EditorTool clip =
                        new ESRI.ArcGIS.ADF.ArcGISServer.Editor.Tools.EditorTool("Clip",
                        ((ESRI.ArcGIS.ADF.ArcGISServer.Editor.EditExistingFeaturePanel)e.Parent).ParentEditor.MapID, false,
                        ESRI.ArcGIS.ADF.ArcGISServer.Editor.Tools.ToolGeometry.Line | ESRI.ArcGIS.ADF.ArcGISServer.Editor.Tools.ToolGeometry.Polygon, 1);
                    clip.ClientAction = ESRI.ArcGIS.ADF.Web.UI.WebControls.Constants.HTML_DRAG_RECTANGLE;
                    clip.DefaultImage = "~/images/clip.png";
                    clip.SelectedImage = "~/images/clip_ON.png";
                    clip.HoverImage = "~/images/clip_OVER.png";
                    clip.ToolTip = "Clip feature(s)";                    
                    clip.ServerActionAssembly = "App_Code";
                    clip.ServerActionClass = "CustomEditorTools.ClipFeatures";

                    editorToolbar.ToolbarItems.Add(clip);
                    
                    // Resize the toolbar to see the new tool.
                    editorToolbar.Width = new Unit(editorToolbar.Width.Value + 35, UnitType.Pixel);
                }
            }

            // Add a new EditorToolbar to the EditExistingFeaturesPanel.  The EditorToolbar will 
            // automatically set the toolbar group to other EditorToolbars in the Editor.
            ESRI.ArcGIS.ADF.ArcGISServer.Editor.Tools.EditorToolbar newEditorToolbar =
                new ESRI.ArcGIS.ADF.ArcGISServer.Editor.Tools.EditorToolbar();
            newEditorToolbar.ToolbarStyle = ESRI.ArcGIS.ADF.Web.UI.WebControls.ToolbarStyle.ImageOnly;
            newEditorToolbar.ID = "MyCustomToolbar";
            newEditorToolbar.BuddyControlType = ESRI.ArcGIS.ADF.Web.UI.WebControls.BuddyControlType.Map;
            newEditorToolbar.BuddyControls.Add(new ESRI.ArcGIS.ADF.Web.UI.WebControls.BuddyControl(
                ((ESRI.ArcGIS.ADF.ArcGISServer.Editor.EditExistingFeaturePanel)e.Parent).ParentEditor.MapID));

            ESRI.ArcGIS.ADF.ArcGISServer.Editor.Tools.EditorCommand vertCount =
                new ESRI.ArcGIS.ADF.ArcGISServer.Editor.Tools.EditorCommand("VerticeCount", ESRI.ArcGIS.ADF.ArcGISServer.Editor.Tools.ToolGeometry.All, 1);
            vertCount.DefaultImage = "~/images/verticecount.png";
            vertCount.SelectedImage = "~/images/verticecount_ON.png";
            vertCount.HoverImage = "~/images/verticecount_OVER.png";
            vertCount.ToolTip = "Count the number of vertices in the selected feature";
            vertCount.ServerActionAssembly = "App_Code";
            vertCount.ServerActionClass = "CustomEditorTools.VerticeCount";

            newEditorToolbar.ToolbarItems.Add(vertCount);
            // If Width is 0, JavaScript error Toolbars[..] is null
            newEditorToolbar.Width = new Unit(newEditorToolbar.ToolbarItems.Count * 35, UnitType.Pixel);

            e.Toolbars.Add(newEditorToolbar);
        }
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        // Generate JavaScript callback function to release server context for non-pooled services.
        m_closeOutCallback = Page.ClientScript.GetCallbackEventReference(Page, "argument", "CloseOutResponse", "context", true);

        // Set attribute filtering parameters for the EditorTask during the 
        // Page Load event of the initial request.
        if (!this.Page.IsPostBack)
        {
            FilterAttributes();
        }
    }

    private void FilterAttributes()
    {
        // Get the ArcGIS Server Local MapFunctionality associated with the EditorTask
        ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.MapFunctionality agsLocalMapFunctionality =
            EditorTask1.Editor.MapFunctionality;

        string[] layerIDs = null;
        string[] layerNames = null;
        agsLocalMapFunctionality.GetLayers(out layerIDs, out layerNames);

        // Iterate through feature layers in the MapFunction (map resource) and set
        // attribute display parameters when editing attributes in the EditAttributesPanel.
        for (int i = 0; i < layerIDs.Length; i++)
        {
            string layerName = layerNames[i];
            int layerID = Int32.Parse(layerIDs[i]);
            if (layerName == "Tentative Assessed Parcels")
            {
                AttributeDisplayInfo attributeDisplayInfo = 
                    new AttributeDisplayInfo(layerID, AttributeDisplayMode.ReadOnly);
                attributeDisplayInfo.Overrides.Add(
                    new AttributeDisplayOverride("APN", AttributeDisplayMode.Editable));
                EditorTask1.AttributeDisplay.AttributeDisplayInfos.Add(attributeDisplayInfo);
            }
            else if (layerName == "Address Points")
            {
                AttributeDisplayInfo attributeDisplayInfo = 
                    new AttributeDisplayInfo(layerID, AttributeDisplayMode.Editable);
                attributeDisplayInfo.Overrides.Add(
                    new AttributeDisplayOverride("APN", AttributeDisplayMode.ReadOnly));
                EditorTask1.AttributeDisplay.AttributeDisplayInfos.Add(attributeDisplayInfo);
            }
            else if (layerName == "Water Bodies")
            {
                AttributeDisplayInfo attributeDisplayInfo = 
                    new AttributeDisplayInfo(layerID, AttributeDisplayMode.Hidden);
                attributeDisplayInfo.Overrides.Add(
                    new AttributeDisplayOverride("NAME", AttributeDisplayMode.Editable));
                EditorTask1.AttributeDisplay.AttributeDisplayInfos.Add(attributeDisplayInfo);
            }
        }
    }

    #region Release server context for non-pooled services
    protected void Page_PreRender(object sender, EventArgs e)
    {
        Session["HasNonPooledResources"] = HasNonPooledResources();
    }

    #region ICallbackEventHandler Members

    string ICallbackEventHandler.GetCallbackResult()
    {
        return m_callbackArg;
    }

    void ICallbackEventHandler.RaiseCallbackEvent(string eventArgument)
    {
        m_callbackArg = eventArgument;

        // parse the callback request
        string[] keyValuePairs = eventArgument.Split("&".ToCharArray());
        if (keyValuePairs.Length > 0)
        {
            string[] keyValue = keyValuePairs[0].Split("=".ToCharArray());

            if (keyValue[0] == "EventArg" && keyValue[1] == "Dispose")
            {
                // Release server context for non-pooled services               
                if ((bool)Session["HasNonPooledResources"])
                    ReleaseContext();
            }
        }
    }

    #endregion

    private void ReleaseContext()
    {
        Response.BufferOutput = true;

        // Close out session and quit application
        IServerContext context;
        for (int i = 0; i < Session.Count; i++)
        {
            context = Session[i] as IServerContext;
            if (context != null)
            {
                context.RemoveAll();
                context.ReleaseContext();
            }
        }
        Session.RemoveAll();

        // clear out response since client is closed or has already gone elsewhere
        Response.Clear();
        Response.End();
    }

    private bool HasNonPooledResources()
    {
        // define a boolean and set it to false by default... no non-pooled resourceitems
        bool hasNonPooledResource = false;
        // Now go through all resources and find any non-pooled local resources
        ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.MapResourceLocal mapResource = null;
        ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.GISDataSourceLocal localDataSource = null;
        // First, check the map resourceitems
        foreach (ESRI.ArcGIS.ADF.Web.UI.WebControls.MapResourceItem mri in MapResourceManager1.ResourceItems)
        {
            if (mri != null)
            {
                mapResource = mri.Resource as ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.MapResourceLocal;

                if (mapResource != null)
                {
                    if (!MapResourceManager1.IsInitialized(mri))
                        MapResourceManager1.Initialize(mri);

                    ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.MapResourceLocal localRes = mapResource as ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.MapResourceLocal;
                    localDataSource = mapResource.DataSource as ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.GISDataSourceLocal;
                    if (!localDataSource.Connection.IsServerObjectPooled(mapResource.ServerContextInfo.ServerObjectName, "MapServer")) hasNonPooledResource = true;

                }
            }
        }
        return hasNonPooledResource;
    }
    #endregion
}