Common_PostbackManager_CSharp\PostbackManager_CSharp\PostbackManager.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 PostbackManager_CSharp { #region PostbackManager Implementation [AjaxControlToolkit.ClientScriptResource("PostbackManager_CSharp.PostbackManager", "PostbackManager_CSharp.JavaScript.PostbackManager.js")] public class PostbackManager: ESRI.ArcGIS.ADF.Web.UI.WebControls.WebControl { #region Member Variables // Stores the argument passed to the server during asynchronous requests private string _callbackArgument = null; // Stores user-specified custom arguments to be passed to the client tier requestProcessed event private string _customResults = null; // Delegate for the RequestReceived events private PostbackManager_CSharp.RequestReceivedEventHandler _requestReceivedHandler; #endregion #region Public Properties - ExposeAdfRequestEvents, CustomResults /// <summary> /// Enables event handling for requests initiated by Web ADF controls. When true, all Web ADF requests /// will be re-routed through the PostbackManager. /// </summary> [System.ComponentModel.Category("PostbackManager"), System.ComponentModel.DefaultValue(true), System.ComponentModel.Description("Enables event handling for requests initiated by Web ADF controls"), System.Web.UI.PersistenceMode(System.Web.UI.PersistenceMode.Attribute)] public bool ExposeAdfRequestEvents { get { return (this.StateManager.GetProperty("ExposeAdfRequestEvents") == null) ? true : (bool)this.StateManager.GetProperty("ExposeAdfRequestEvents"); } set { this.StateManager.SetProperty("ExposeAdfRequestEvents", value); } } /// <summary> /// Stores properties that are returned to the client via the arguments object passed to the client tier /// requestProcessed event. Can be used to pass data to the client without manipulating callback results. /// </summary> [System.ComponentModel.Browsable(false)] public string CustomResults { get { return _customResults; } set { _customResults = value; } } #endregion #region ASP.NET WebControl Life Cycle Event Overrides - OnPreRender, RenderContents // Registers script to create the client tier singleton PostbackManager instance protected override void OnPreRender(System.EventArgs e) { base.OnPreRender(e); // Only execute initialization logic during full page postbacks if (base.IsAsync) return; // Initialize a dictionary with the properties needed to initialize the client tier // PostbackManager singleton instance System.Collections.Generic.Dictionary<string, object> clientPropertyDictionary = new System.Collections.Generic.Dictionary<string, object>(); clientPropertyDictionary.Add("uniqueID", this.UniqueID); clientPropertyDictionary.Add("callbackFunctionString", this.CallbackFunctionString); clientPropertyDictionary.Add("exposeAdfRequestEvents", this.ExposeAdfRequestEvents); // Serialize the properties to JSON System.Web.Script.Serialization.JavaScriptSerializer jsSerializer = new System.Web.Script.Serialization.JavaScriptSerializer(); string clientPropertyJson = jsSerializer.Serialize(clientPropertyDictionary); // Construct JavaScript to instantiate the client tier PostbackManager singleton string scriptKey = "ESRI_PostbackManager_Script"; string initializationScript = @"Sys.Application.add_init(function() {{ if (ESRI.ADF.Samples.PostbackManager) return; ESRI.ADF.Samples.PostbackManager = $create(ESRI.ADF.Samples._PostbackManager, {0}, null, null, $get('{1}')); }});"; initializationScript = string.Format(initializationScript, clientPropertyJson, this.ClientID); // Register the script to execute on application startup System.Web.UI.ScriptManager.RegisterStartupScript(this, this.GetType(), scriptKey, initializationScript, true); } // Creates a design-time representation of the control protected override void RenderContents(System.Web.UI.HtmlTextWriter writer) { if (this.DesignMode) this.RenderDesignTimeHtml(writer); else base.RenderContents(writer); } #endregion #region ICallbackEventHandler Overrides - GetCallbackResult, RaiseCallbackEvent // Initiates callback events on the calling control, raises the RequestReceived event, // and constructs script to invoke the client tier requestProcessed event public override string GetCallbackResult() { // Parse the callback arguments into a name-value collection System.Collections.Specialized.NameValueCollection callbackArgs = ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackUtility.ParseStringIntoNameValueCollection(_callbackArgument); string callingControlID = callbackArgs["ControlID"]; // Make sure a calling control was specified in the request arguments if (callingControlID != null) { // Retrieve the calling control System.Web.UI.Control callingControl = PostbackManager_CSharp.PostbackManager.FindControlByClientID(this.Page, callingControlID); // Fire the RequestReceived event PostbackManager_CSharp.AdfRequestEventArgs requestReceivedArgs = new PostbackManager_CSharp.AdfRequestEventArgs(callingControl, _callbackArgument); this.OnRequestReceived(requestReceivedArgs); // Invoke ICallbackEventHandler members on the calling control if that control is not the // PostbackManager. This also copies callback results from the calling control. if (callingControl != this) this.DoCallerCallback(callingControl, _callbackArgument); // Convert callback results into a JSON serializable object System.Web.Script.Serialization.JavaScriptSerializer jsSerializer = new System.Web.Script.Serialization.JavaScriptSerializer(); object callbackResults = null; if (this.CallbackResults.ToString() != null) callbackResults = jsSerializer.DeserializeObject(this.CallbackResults.ToString()); // Initialize a dictionary with the results to be returned to the client tier // requestProcessed event System.Collections.Generic.Dictionary<string, object> resultsDictionary = new System.Collections.Generic.Dictionary<string, object>(); resultsDictionary.Add("callingControlID", callingControlID); resultsDictionary.Add("callbackResults", callbackResults); resultsDictionary.Add("customResults", this.CustomResults); // Serialize the results to JSON string resultsJson = jsSerializer.Serialize(resultsDictionary); // Embed JavaScript to invoke the client tier requestProcessed event in a callback result string raiseRequestProcessedScript = string.Format( "ESRI.ADF.Samples.PostbackManager._raiseEvent('requestProcessed', {0});", resultsJson); this.CallbackResults.Add( ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult.CreateJavaScript(raiseRequestProcessedScript)); } return this.CallbackResults.ToString(); } // Retrieves the argument passed to the server public override void RaiseCallbackEvent(string eventArgument) { base.RaiseCallbackEvent(eventArgument); _callbackArgument = eventArgument; } #endregion #region IPostBackEventHandler Overrides - RaisePostBackEvent // Invokes web tier asynchronous request handling logic public override void RaisePostBackEvent(string eventArgument) { this.RaiseCallbackEvent(eventArgument); base.RaisePostBackEvent(eventArgument); } #endregion #region Event Wiring - RequestReceived /// <summary> /// Occurs when the web request has reached the server, but before the request has been processed /// on the server by the Web ADF control initiating the request. /// </summary> public event RequestReceivedEventHandler RequestReceived { add { _requestReceivedHandler += value; } remove { _requestReceivedHandler -= value; } } /// <summary> /// Raises the RequestReceived event. /// </summary> /// <param name="args">A RequestProcessingEventArgs object that contains the Web ADF control that initiated the request.</param> protected virtual void OnRequestReceived(PostbackManager_CSharp.AdfRequestEventArgs args) { if (_requestReceivedHandler != null) _requestReceivedHandler(this, args); } #endregion #region Private Methods // Calls RaiseCallbackEvent and GetCallbackResult on the passed-in control and copies callback results to // the PostbackManager private void DoCallerCallback(System.Web.UI.Control control, string callbackArgument) { // Check which type of Web ADF base control the passed-in control is. Then invoke the control's // callback event methods and copy its callback results. if (control is ESRI.ArcGIS.ADF.Web.UI.WebControls.WebControl) { ESRI.ArcGIS.ADF.Web.UI.WebControls.WebControl webControl = control as ESRI.ArcGIS.ADF.Web.UI.WebControls.WebControl; webControl.RaiseCallbackEvent(callbackArgument); webControl.GetCallbackResult(); this.CallbackResults.CopyFrom(webControl.CallbackResults); } else if (control is ESRI.ArcGIS.ADF.Web.UI.WebControls.CompositeControl) { ESRI.ArcGIS.ADF.Web.UI.WebControls.CompositeControl compositeControl = control as ESRI.ArcGIS.ADF.Web.UI.WebControls.CompositeControl; compositeControl.RaiseCallbackEvent(callbackArgument); compositeControl.GetCallbackResult(); this.CallbackResults.CopyFrom(compositeControl.CallbackResults); } } // Searches the passed-in control and all its child controls, returning that having the passed-in // client ID, if found private static System.Web.UI.Control FindControlByClientID(System.Web.UI.Control rootControl, string controlID) { // Return the passed-in control if it has the passed-in ID if (rootControl.ClientID == controlID) return rootControl; // Iterate through the control's child controls, recursively calling FindControl on each. // If at any point a control with the passed-in ID is found, return it. foreach (System.Web.UI.Control childControl in rootControl.Controls) { System.Web.UI.Control foundControl = FindControlByClientID(childControl, controlID); if (foundControl != null) return foundControl; } return null; } // Renders the control at design-time private void RenderDesignTimeHtml(System.Web.UI.HtmlTextWriter writer) { // Create a table to format the design-time display System.Web.UI.WebControls.Table table = new System.Web.UI.WebControls.Table(); table.Font.Name = this.Font.Name; table.Font.Size = this.Font.Size; table.Style[System.Web.UI.HtmlTextWriterStyle.BackgroundColor] = "white"; table.BorderColor = System.Drawing.Color.Black; table.BorderStyle = System.Web.UI.WebControls.BorderStyle.Solid; table.BorderWidth = 1; System.Web.UI.WebControls.TableRow row = new System.Web.UI.WebControls.TableRow(); table.CellPadding = 4; table.Rows.Add(row); // Add the control's ID System.Web.UI.WebControls.TableCell cell = new System.Web.UI.WebControls.TableCell(); row.Cells.Add(cell); cell.Style[System.Web.UI.HtmlTextWriterStyle.WhiteSpace] = "nowrap"; cell.Text = string.Format("{0}<br>", this.ClientID); row = new System.Web.UI.WebControls.TableRow(); table.Rows.Add(row); // Add the control type cell = new System.Web.UI.WebControls.TableCell(); row.Cells.Add(cell); cell.Text = "PostbackManager WebControl"; table.RenderControl(writer); } #endregion } #endregion #region Event Delegate and Argument Classes - RequestReceivedEventHandler, AdfRequestEventArgs /// <summary>Delegate to handle the RequestReceived event.</summary> /// <param name="sender">The PostbackManager Control that initiated the event.</param> /// <param name="args">Arguments that include the ADF Control that initiated the request.</param> public delegate void RequestReceivedEventHandler(object sender, PostbackManager_CSharp.AdfRequestEventArgs args); /// <summary>Event arguments for a Web ADF asyncrhonous request.</summary> public class AdfRequestEventArgs : System.EventArgs { private System.Web.UI.Control _callingControl; private string _requestArguments; /// <summary>Constructor.</summary> /// <param name="callingControl">The Web ADF control that initiated the request.</param> /// <param name="requestArguments">The arguments passed to the server in the request.</param> public AdfRequestEventArgs(System.Web.UI.Control callingControl, string requestArguments) { _callingControl = callingControl; _requestArguments = requestArguments; } /// <summary>The Web ADF control that initiated the request.</summary> public System.Web.UI.Control CallingControl { get { return _callingControl; } } /// <summary>The arguments passed along with the request.</summary> public string RequestArguments { get { return _requestArguments; } } } #endregion }