Common Timer redraw
Common_TimerRedraw_CSharp\ThreadedUpdate.aspx.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.
// 

public partial class ThreadedUpdate : System.Web.UI.Page
{
    #region Member Variables

    // Name of the resource to add graphics to
    private string _graphicsResourceName = "GraphicsResource";

    // Amount of time to wait for the operation to complete when executing is initiated, in milliseconds
    private int _initialWaitTime = 2000;

    // Amount of time to add to the execution of retrieving new graphics, in milliseconds
    private int _simulatedOperationLength = 5000;

    // Key for session variable indicating whether graphics drawing is complete
    private string drawCompleteSessionKey = "DrawComplete";

    // Array containing the names of the 48 contiguous states.  Used in creating feature graphics for a 
    // random subset of these states.
    private string[] _states = { "Alabama","Arizona","Arkansas","California","Colorado","Connecticut",
        "Delaware","Florida","Georgia","Idaho","Illinois","Indiana","Iowa","Kansas","Kentucky","Louisiana",
        "Maine","Maryland","Massachusetts","Michigan","Minnesota","Mississippi","Missouri","Montana",
        "Nebraska","Nevada","New Hampshire","New Jersey","New Mexico","New York","North Carolina",
        "North Dakota","Ohio","Oklahoma","Oregon","Pennsylvania","Rhode Island","South Carolina","South Dakota",
        "Tennessee","Texas","Utah","Vermont","Virginia","Washington","West Virginia","Wisconsin","Wyoming" };

    #endregion

    #region Event Handlers - Page_Load, RequestReceived

    protected void Page_PreRender(object sender, System.EventArgs e)
    {
        // Initialize the session variable that indicates whether the current operation has completed
        if (!this.IsAsync && this.Session[drawCompleteSessionKey] == null)
            this.Session[drawCompleteSessionKey] = false;
    }

    protected void Page_Load(object sender, System.EventArgs e)
    {
        // Add a handler for the PostbackManager's RequestReceived event.  This event fires whenever doAsyncRequest
        // is called on on the client tier PostbackManager.  For more information on the PostbackManager, see the
        // Common_PostbackManager sample.
        PostbackManager1.RequestReceived +=
            new PostbackManager_CSharp.RequestReceivedEventHandler(PostbackManager1_RequestReceived);
    }

    // Fires when a request is received that was initiated by a call to PostbackManager.doAsyncRequest on the client
    void PostbackManager1_RequestReceived(object sender, PostbackManager_CSharp.AdfRequestEventArgs args)
    {
        // Parse the request arguments
        System.Collections.Specialized.NameValueCollection requestArgs =
            ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackUtility.ParseStringIntoNameValueCollection(args.RequestArguments);

        // Indicates whether the graphics resource needs to be refreshed
        bool refreshGraphics = false;

        // Check the event argument and draw or clear graphics accordingly
        switch (requestArgs["EventArg"])
        {
            case "DrawGraphics":
                // Get the current time
                System.DateTime startTime = System.DateTime.Now;

                // Invoke the graphics drawing logic on a new thread
                System.Threading.WaitCallback drawGraphicsCallback =
                    new System.Threading.WaitCallback(DrawGraphics);
                System.Threading.ThreadPool.QueueUserWorkItem(drawGraphicsCallback);

                // Initialize a time span that will store the elapsed time since starting the operation
                System.TimeSpan elapsedTime = System.DateTime.Now - startTime;

                // Allow the draw graphics operation the amount of time to complete indicated by _initialWaitTime
                while (elapsedTime.TotalMilliseconds < _initialWaitTime)
                {
                    // Check whether the draw graphics operation is done
                    if ((bool)this.Session[drawCompleteSessionKey])
                    {
                        // The operation is complete, so the graphics resource needs to be refreshed
                        refreshGraphics = true;
                        break;
                    }

                    // Wait half a second before continuing the loop
                    System.Threading.Thread.Sleep(500);

                    // Update the elapsed time
                    elapsedTime = System.DateTime.Now - startTime;
                }
                break;
            case "CheckGraphics":
                // Check whether the draw graphics operation is complete and set the refreshGraphics flag accordingly
                if ((bool)this.Session[drawCompleteSessionKey])
                    refreshGraphics = true;
                break;
            case "ClearGraphics":
                // Call method to clear graphics and set the flag to refresh graphics
                ClearGraphics();
                refreshGraphics = true;
                break;
        }

        if (refreshGraphics)
        {
            // Apply the graphics updates to the map
            Map1.RefreshResource(_graphicsResourceName);
            PostbackManager1.CallbackResults.CopyFrom(Map1.CallbackResults);
            
            // Reset the session variable.  We do this in a lock to avoid thread contention.
            lock (this.Session.SyncRoot)
                this.Session[drawCompleteSessionKey] = false;

            // Set the postback manager's custom results.  These will be used on the client to determine
            // whether to set an update graphics timeout and to update the status text.
            if (requestArgs["EventArg"].Contains("Clear"))
                PostbackManager1.CustomResults = "cleared";
            else
                PostbackManager1.CustomResults = "complete";
        }
        else
        {
            PostbackManager1.CustomResults = "pending";
        }
    }

    #endregion

    #region Private Graphics Manipulation Methods - DrawGraphics, ClearGraphics

    // Draws a random subset of states as feature graphics on the map.  The object parameter is included so the 
    // method can be used to create a WaitCallback.
    private void DrawGraphics(object o)
    {
        // Get the graphics resource
        ESRI.ArcGIS.ADF.Web.DataSources.Graphics.MapFunctionality graphicsMapFunctionality =
            Map1.GetFunctionality(_graphicsResourceName) as ESRI.ArcGIS.ADF.Web.DataSources.Graphics.MapFunctionality;

        // Suspend the thread for the specified simulation duration
        System.Threading.Thread.Sleep(_simulatedOperationLength);

        // Get a query functionality for the USA_Data resource
        string targetResourceName = "USA";
        ESRI.ArcGIS.ADF.Web.DataSources.IMapFunctionality commonMapFunctionality =
            Map1.GetFunctionality(targetResourceName);
        ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality queryFunctionality =
            (ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality)commonMapFunctionality.Resource.CreateFunctionality(
            typeof(ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality), null);

        // Get the names and IDs of the layers in the resource that can be queried
        string[] layerIDs;
        string[] layerNames;
        queryFunctionality.GetQueryableLayers(null, out layerIDs, out layerNames);

        // Get the index of the states layer
        string targetLayerName = "States";
        string targetLayerID = null;
        for (int i = 0; i < layerNames.Length; i++)
        {
            if (layerNames[i].ToLower() == targetLayerName.ToLower())
            {
                targetLayerID = layerIDs[i];
                break;
            }
        }

        // Initialize a filter for querying states
        ESRI.ArcGIS.ADF.Web.QueryFilter adfQueryFilter = new ESRI.ArcGIS.ADF.Web.QueryFilter();
        adfQueryFilter.ReturnADFGeometries = true;
        adfQueryFilter.MaxRecords = 50;

        // Specify that only the STATE_NAME field be queried
        string targetFieldName = "STATE_NAME";
        ESRI.ArcGIS.ADF.StringCollection stringCollection =
            new ESRI.ArcGIS.ADF.StringCollection(targetFieldName, ',');
        adfQueryFilter.SubFields = stringCollection;

        System.Text.StringBuilder stringBuilder =
            new System.Text.StringBuilder();

        // Generate the number of states to display graphics for
        System.Random randomizer = new System.Random();
        int numberStates = randomizer.Next(4, 26);

        // Get a state name from the list
        string stateName = _states[randomizer.Next(_states.Length)];
        // Add the number of unique state names specified by numberStates
        for (int i = 0; i < numberStates; i++)
        {
            // Get the list
            string stateList = stringBuilder.ToString();

            // Keep picking random state names until one is picked that isn't already on the list
            while (stateList.Contains(stateName))
                stateName = _states[randomizer.Next(_states.Length)];

            // Add the state to the list
            stringBuilder.AppendFormat("'{0}',", stateName);
        }

        // Remove the trailing comma from the list
        string whereClause = stringBuilder.ToString();
        whereClause = whereClause.Substring(0, whereClause.Length - 1);

        // Specify that the query filter get features that match the states in the list
        adfQueryFilter.WhereClause = string.Format("STATE_NAME IN ({0})", whereClause);
        
        // Execute the query
        System.Data.DataTable resultsTable = queryFunctionality.Query(
            commonMapFunctionality.Name, targetLayerID, adfQueryFilter);

        // Convert results to a graphics layer and add to the map
        ESRI.ArcGIS.ADF.Web.Display.Graphics.GraphicsLayer resultsGraphicsLayer =
            ESRI.ArcGIS.ADF.Web.UI.WebControls.Converter.ToGraphicsLayer(resultsTable);
        string layerName = "Feature Graphics";
        resultsGraphicsLayer.TableName = layerName;

        // Lock the map functionality while it is being modified to avoid thread contention
        lock (graphicsMapFunctionality)
        {
            if (graphicsMapFunctionality.GraphicsDataSet.Tables.Contains(layerName))
                graphicsMapFunctionality.GraphicsDataSet.Tables.Remove(layerName);
            graphicsMapFunctionality.GraphicsDataSet.Tables.Add(resultsTable);
        }

        // Set the session flag indicating the operation is complete to true.  Lock the session while doing
        // this to avoid thread contention.
        lock (this.Session.SyncRoot)
            this.Session[drawCompleteSessionKey] = true;
    }

    // Removes element or feature graphics from the map
    private void ClearGraphics()
    {
        // Get the graphics resource
        ESRI.ArcGIS.ADF.Web.DataSources.Graphics.MapFunctionality graphicsMapFunctionality =
            Map1.GetFunctionality(_graphicsResourceName) as ESRI.ArcGIS.ADF.Web.DataSources.Graphics.MapFunctionality;

        // Remove the element or feature graphics layer from the resource
        if (graphicsMapFunctionality.GraphicsDataSet.Tables.Contains("Feature Graphics"))
            graphicsMapFunctionality.GraphicsDataSet.Tables.Remove("Feature Graphics");
    }

    #endregion
}