PageRequestManager.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / ndp / fx / src / xsp / System / Web / Extensions / ui / PageRequestManager.cs / 2 / PageRequestManager.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

namespace System.Web.UI { 
    using System; 
    using System.Collections;
    using System.Collections.Generic; 
    using System.Collections.Specialized;
    using System.Diagnostics;
    using System.Globalization;
    using System.IO; 
    using System.Security;
    using System.Text; 
    using System.Web; 
    using System.Web.Configuration;
    using System.Web.UI; 
    using System.Web.UI.HtmlControls;
    using System.Web.Resources;
    using System.Web.Script.Serialization;
    using System.Reflection; 
    using System.Security.Permissions;
 
    internal sealed class PageRequestManager { 

        // Type tokens for partial rendering format 
        internal const string PageRedirectToken = "pageRedirect";
        internal const string HiddenFieldToken = "hiddenField";
        private const string AsyncPostBackControlIDsToken = "asyncPostBackControlIDs";
        private const string PostBackControlIDsToken = "postBackControlIDs"; 
        private const string UpdatePanelIDsToken = "updatePanelIDs";
        private const string AsyncPostBackTimeoutToken = "asyncPostBackTimeout"; 
        private const string ChildUpdatePanelIDsToken = "childUpdatePanelIDs"; 
        private const string UpdatePanelsToRefreshToken = "panelsToRefreshIDs";
        private const string FormActionToken = "formAction"; 
        private const string DataItemToken = "dataItem";
        private const string DataItemJsonToken = "dataItemJson";
        internal const string ArrayDeclarationToken = "arrayDeclaration";
        internal const string ExpandoToken = "expando"; 
        internal const string OnSubmitToken = "onSubmit";
        internal const string ScriptBlockToken = "scriptBlock"; 
        internal const string ScriptStartupBlockToken = "scriptStartupBlock"; 
        internal const string ScriptDisposeToken = "scriptDispose";
        internal const string ErrorToken = "error"; 
        internal const string AsyncPostBackErrorKey = "System.Web.UI.PageRequestManager:AsyncPostBackError";
        internal const string AsyncPostBackErrorMessageKey = "System.Web.UI.PageRequestManager:AsyncPostBackErrorMessage";
        internal const string AsyncPostBackErrorHttpCodeKey = "System.Web.UI.PageRequestManager:AsyncPostBackErrorHttpCode";
        private const string PageTitleToken = "pageTitle"; 
        private const string FocusToken = "focus";
        private const string AsyncPostFormField = "__ASYNCPOST"; 
 
        private const char LengthEncodeDelimiter = '|';
        private static readonly Version MinimumW3CDomVersion = new Version(1, 0); 
        private static readonly Version MinimumEcmaScriptVersion = new Version(1, 0);

        private ScriptManager _owner;
 
        private List _allUpdatePanels;
        private List _updatePanelsToRefresh; 
        private List _childUpdatePanelsToRefresh; 
        private List _asyncPostBackControls;
        private List _postBackControls; 
        private ScriptDataItemCollection _scriptDataItems;
        private string _updatePanelRequiresUpdate;
        private HtmlTextWriter _updatePanelWriter;
        private bool _panelsInitialized; 
        private string _asyncPostBackSourceElementID;
 
        // Stolen from Whidbey Page.cs for focus support 
        private static readonly Version FocusMinimumEcmaVersion = new Version("1.4");
        private static readonly Version FocusMinimumJScriptVersion = new Version("3.0"); 
        private string _focusedControlID;
        private Control _focusedControl;
        private bool _requireFocusScript;
 
        public PageRequestManager(ScriptManager owner) {
            Debug.Assert(owner != null); 
            _owner = owner; 
        }
 

        public string AsyncPostBackSourceElementID {
            get {
                if (_asyncPostBackSourceElementID == null) { 
                    return String.Empty;
                } 
                return _asyncPostBackSourceElementID; 
            }
        } 

        // Stolen from Whidbey Page.cs
        private bool ClientSupportsFocus {
            get { 
                HttpBrowserCapabilitiesBase browser = _owner.IPage.Request.Browser;
                return 
                    (browser.EcmaScriptVersion >= FocusMinimumEcmaVersion) || 
                    (browser.JScriptVersion >= FocusMinimumJScriptVersion);
            } 
        }

        private bool EnableLegacyRendering {
            get { 
                return _owner.EnableLegacyRendering;
            } 
        } 

        [SecurityCritical()] 
        [SecurityTreatAsSafe()]
        private bool CustomErrorsSectionHasRedirect(int httpCode) {
            bool hasRedirect = (_owner.CustomErrorsSection.DefaultRedirect != null);
            if (!hasRedirect) { 
                if (_owner.CustomErrorsSection.Errors != null) {
                    foreach (CustomError error in _owner.CustomErrorsSection.Errors) { 
                        if (error.StatusCode == httpCode) { 
                            hasRedirect = true;
                            break; 
                        }
                    }
                }
            } 
            return hasRedirect;
        } 
 
        // Optimized version of EncodeString that writes directly to a writer. This
        // eliminates the need to create several copies of the same string as well 
        // as a StringBuilder.
        internal static void EncodeString(TextWriter writer, string type, string id, string content) {
            Debug.Assert(!String.IsNullOrEmpty(type), "Type should always be specified");
            if (id == null) { 
                id = String.Empty;
            } 
            if (content == null) { 
                content = String.Empty;
            } 
            Debug.Assert(type.IndexOf(LengthEncodeDelimiter) == -1, "Should not be a " + LengthEncodeDelimiter + " in type");
            Debug.Assert(id.IndexOf(LengthEncodeDelimiter) == -1, "Should not be a " + LengthEncodeDelimiter + " in id");

            // len|type|id|content| 
            //             -------   len
 
            writer.Write(content.Length.ToString(CultureInfo.InvariantCulture)); 
            writer.Write(LengthEncodeDelimiter);
            writer.Write(type); 
            writer.Write(LengthEncodeDelimiter);
            writer.Write(id);
            writer.Write(LengthEncodeDelimiter);
            // DevDiv 75383: We used to escape null characters from the content, but this had a non trivial hit on perf 
            // They were escaped because XMLHttpRequest in IE truncates content after a null character.
            // However, when HTML contains a null character, subsequent content is truncated anyway, so the value of escaping nulls 
            // in the first place is not clear and it was decided it is not worth the perf hit. 
            writer.Write(content);
            writer.Write(LengthEncodeDelimiter); 
        }

        private string GetAllUpdatePanelIDs() {
            return GetUpdatePanelIDsFromList(_allUpdatePanels, true); 
        }
 
        private string GetAsyncPostBackControlIDs(bool includeQuotes) { 
            return GetControlIDsFromList(_asyncPostBackControls, includeQuotes);
        } 

        private string GetChildUpdatePanelIDs() {
            return GetUpdatePanelIDsFromList(_childUpdatePanelsToRefresh, false);
        } 

        private static string GetControlIDsFromList(List list, bool includeQuotes) { 
            if (list != null && list.Count > 0) { 
                StringBuilder asyncPostBackControlIDs = new StringBuilder();
                bool first = true; 
                for (int i = 0; i < list.Count; i++) {
                    if (!list[i].Visible) {
                        // If the panel isn't visible, the client doesn't need to know about it
                        continue; 
                    }
                    if (!first) { 
                        asyncPostBackControlIDs.Append(','); 
                    }
                    first = false; 
                    if (includeQuotes) {
                        asyncPostBackControlIDs.Append('\'');
                    }
                    asyncPostBackControlIDs.Append(list[i].UniqueID); 
                    if (includeQuotes) {
                        asyncPostBackControlIDs.Append('\''); 
                    } 
                }
                return asyncPostBackControlIDs.ToString(); 
            }
            return String.Empty;
        }
 
        private static Exception GetControlRegistrationException(Control control) {
            // DevDiv Bugs 145573: It is ok to register the Page as an async/postback control 
            if (control == null) { 
                return new ArgumentNullException("control");
            } 
            if (!(control is INamingContainer) &&
                !(control is IPostBackDataHandler) &&
                !(control is IPostBackEventHandler)) {
                return new ArgumentException(String.Format(CultureInfo.InvariantCulture, AtlasWeb.ScriptManager_InvalidControlRegistration, control.ID)); 
            }
            return null; 
        } 

        // This code is roughly stolen from HttpException.GetHttpCodeForException() 
        private static int GetHttpCodeForException(Exception e) {
            HttpException he = e as HttpException;
            if (he != null) {
                return he.GetHttpCode(); 
            }
            else if (e is UnauthorizedAccessException) { 
                return 401; 
            }
            else if (e is PathTooLongException) { 
                return 414;
            }

            // If there is an inner exception, try to get the code from it 
            if (e.InnerException != null)
                return GetHttpCodeForException(e.InnerException); 
 
            // If all else fails, use 500
            return 500; 
        }

        private string GetPostBackControlIDs(bool includeQuotes) {
            return GetControlIDsFromList(_postBackControls, includeQuotes); 
        }
 
        private string GetRefreshingUpdatePanelIDs() { 
            return GetUpdatePanelIDsFromList(_updatePanelsToRefresh, false);
        } 

        private static string GetUpdatePanelIDsFromList(List list, bool includeChildrenAsTriggersPrefix) {
            if (list != null && list.Count > 0) {
                StringBuilder updatePanelIDs = new StringBuilder(); 
                bool first = true;
                for (int i = 0; i < list.Count; i++) { 
                    if (!list[i].Visible) { 
                        // If the panel isn't visible, the client doesn't need to know about it
                        continue; 
                    }
                    if (!first) {
                        updatePanelIDs.Append(',');
                    } 
                    first = false;
                    // We send down the UniqueID instead of the ClientID because 
                    // we need both versions on the client. You can convert from 
                    // UniqueID to ClientID, but not back.
 
                    // We also send down a bool indicating whether the children of
                    // the panel count as triggers or not.
                    if (includeChildrenAsTriggersPrefix) {
                        updatePanelIDs.Append(list[i].ChildrenAsTriggers ? 't' : 'f'); 
                    }
                    updatePanelIDs.Append(list[i].UniqueID); 
                } 
                return updatePanelIDs.ToString();
            } 
            return String.Empty;
        }

        internal static bool IsAsyncPostBackRequest(HttpRequestBase request) { 
            // Detect the header for async postbacks. A header can appear
            // multiple times, and each header entry can contain a comma-separated 
            // list of values. ASP.NET doesn't split the comma-separated values for 
            // us so we have to do it.
 
            // We used to use the Pragma header but some browsers, such as Opera,
            // do not support sending it through XMLHttpRequest. Instead we use a
            // custom header, X-MicrosoftAjax.
            string[] headerValues = request.Headers.GetValues("X-MicrosoftAjax"); 
            if (headerValues != null) {
                for (int i = 0; i < headerValues.Length; i++) { 
                    string[] headerContents = headerValues[i].Split(','); 
                    for (int j = 0; j < headerContents.Length; j++) {
                        if (headerContents[j].Trim() == "Delta=true") { 
                            return true;
                        }
                    }
                } 
            }
            // DevDiv Bugs 188713: X-MicrosoftAjax header is stripped by some firewalls 
            string asyncPost = request.Form[AsyncPostFormField]; 
            return !String.IsNullOrEmpty(asyncPost) &&
                (asyncPost.Trim() == "true"); 
        }

        internal void LoadPostData(string postDataKey, NameValueCollection postCollection) {
            // Check if the async postback was caused by a specific panel, and if so, force 
            // that panel to update, regardless of whether it had any explicit triggers, etc.
            // If the post back data starts with the ScriptManager's UniqueID that means the 
            // async postback was caused by a control outside of an UpdatePanel, and the rest 
            // of the string is the UniqueID of that control.
            string postBackSourceInfo = postCollection[postDataKey]; 
            if (postBackSourceInfo != null) {
                string postBackTarget; // The target of the postback - either the ScriptManager or an UpdatePanel

                int indexOfPipe = postBackSourceInfo.IndexOf('|'); 
                if (indexOfPipe != -1) {
                    // We have a target and source element 
                    postBackTarget = postBackSourceInfo.Substring(0, indexOfPipe); 
                    _asyncPostBackSourceElementID = postBackSourceInfo.Substring(indexOfPipe + 1);
                } 
                else {
                    // We only have a target
                    postBackTarget = postBackSourceInfo;
                    _asyncPostBackSourceElementID = String.Empty; 
                }
 
                if (postBackTarget != _owner.UniqueID) { 
                    _updatePanelRequiresUpdate = postBackTarget;
                } 
            }

            // Initialize all UpdatePanels (and their triggers, specifically) so that
            // they can hook events, etc. before other controls can process their 
            // own post data.
            // LoadPostData on ScriptManager only gets called during async posts, and 
            // is guaranteed to be called before any other controls have a chance to 
            // process their post data.
            // During regular posts the UpdatePanel initializes itself in OnLoad. 
            if ((_allUpdatePanels != null) && (_allUpdatePanels.Count != 0)) {
                foreach (UpdatePanel panel in _allUpdatePanels) {
                    panel.Initialize();
                } 
            }
 
            _panelsInitialized = true; 
        }
 
        internal void OnInit() {
            // Check if the browser supports partial rendering. We only do the check
            // if the user hasn't already forced the feature to be on or off explicitly.
            if (_owner.EnablePartialRendering && !_owner._supportsPartialRenderingSetByUser) { 
                HttpBrowserCapabilitiesBase browser = _owner.IPage.Request.Browser;
                // There is no browser cap that directly tells us whether the browser 
                // supports XmlHttpRequest so we use the next best capability, which is 
                // the SupportsCallback property.
                // Checking the other properties helps exclude agents such as crawlers. 
                bool supportsPartialRendering =
                    (browser.W3CDomVersion >= MinimumW3CDomVersion) &&
                    (browser.EcmaScriptVersion >= MinimumEcmaScriptVersion) &&
                    browser.SupportsCallback; 
                if (supportsPartialRendering) {
                    // If we still think we want to support it, now do a more expensive 
                    // check for XHTML legacy rendering support. 
                    supportsPartialRendering = !EnableLegacyRendering;
                } 
                _owner.SupportsPartialRendering = supportsPartialRendering;
            }

            if (_owner.IsInAsyncPostBack) { 
                _owner.IPage.Error += OnPageError;
            } 
        } 

        private void OnPageError(object sender, EventArgs e) { 
            Exception ex = _owner.IPage.Server.GetLastError();
            _owner.OnAsyncPostBackError(new AsyncPostBackErrorEventArgs(ex));

            string errorMessage = _owner.AsyncPostBackErrorMessage; 
            if (String.IsNullOrEmpty(errorMessage) && !_owner.Control.Context.IsCustomErrorEnabled) {
                // Only use the exception's message if we're not doing custom errors 
                errorMessage = ex.Message; 
            }
 
            int httpCode = GetHttpCodeForException(ex);

            bool showAsyncErrorMessage = false;
 
            if (_owner.AllowCustomErrorsRedirect && _owner.Control.Context.IsCustomErrorEnabled) {
                // Figure out if there's going to be a redirect for this error 
                bool hasRedirect = CustomErrorsSectionHasRedirect(httpCode); 
                if (!hasRedirect) {
                    // If there's no redirect, we need to send back the error message 
                    showAsyncErrorMessage = true;
                }
                // If there was a redirect we do nothing since ASP.NET will automatically
                // redirect the user to the error page anyway. This way we don't have to 
                // worry about how to resolve the paths from config.
            } 
            else { 
                // If we're not going to use custom errors, just send back the error message
                showAsyncErrorMessage = true; 
            }

            if (showAsyncErrorMessage) {
                IDictionary items = _owner.Control.Context.Items; 
                items[AsyncPostBackErrorKey] = true;
                items[AsyncPostBackErrorMessageKey] = errorMessage; 
                items[AsyncPostBackErrorHttpCodeKey] = httpCode; 
            }
        } 

        internal void OnPreRender() {
            _owner.IPage.SetRenderMethodDelegate(RenderPageCallback);
        } 

        private void ProcessFocus(HtmlTextWriter writer) { 
            // Roughly stolen from Whidbey Page.cs 
            if (_requireFocusScript) {
                Debug.Assert(ClientSupportsFocus, "If ClientSupportsFocus is false then we never should have set _requireFocusScript to true."); 
                string focusedControlId = String.Empty;

                // Someone calling SetFocus(controlId) has the most precedent
                if (!String.IsNullOrEmpty(_focusedControlID)) { 
                    focusedControlId = _focusedControlID;
                } 
                else { 
                    if (_focusedControl != null && _focusedControl.Visible) {
                        focusedControlId = _focusedControl.ClientID; 
                    }
                }
                if (focusedControlId.Length > 0) {
                    // Register focus script library 
                    string focusResourceUrl = _owner.GetScriptResourceUrl("Focus.js", typeof(HtmlForm).Assembly);
                    EncodeString(writer, ScriptBlockToken, "ScriptPath", focusResourceUrl); 
 
                    // Send the target control ID to the client
                    EncodeString(writer, FocusToken, String.Empty, focusedControlId); 
                }
            }
        }
 
        private void ProcessScriptRegistration(HtmlTextWriter writer) {
            _owner.ScriptRegistration.RenderActiveArrayDeclarations(_updatePanelsToRefresh, writer); 
            _owner.ScriptRegistration.RenderActiveScripts(_updatePanelsToRefresh, writer); 
            _owner.ScriptRegistration.RenderActiveSubmitStatements(_updatePanelsToRefresh, writer);
            _owner.ScriptRegistration.RenderActiveExpandos(_updatePanelsToRefresh, writer); 
            _owner.ScriptRegistration.RenderActiveHiddenFields(_updatePanelsToRefresh, writer);
            _owner.ScriptRegistration.RenderActiveScriptDisposes(_updatePanelsToRefresh, writer);
        }
 
        private void ProcessUpdatePanels() {
            Debug.Assert(_owner.IsInAsyncPostBack); 
            Debug.Assert(_updatePanelsToRefresh == null); 

            if (_allUpdatePanels != null) { 
                _updatePanelsToRefresh = new List(_allUpdatePanels.Count);
                _childUpdatePanelsToRefresh = new List(_allUpdatePanels.Count);

                // Process the UpdatePanels to determine which are to be set in 
                // partial rendering mode.
 
                // We need to process the list such that parent UpdatePanels are 
                // evaluated first. A child UpdatePanel inside a parent that is being
                // updated should not be considered in partial rendering mode. 
                // Ordinarily child controls get initialized first before their parents
                // so you'd expect the list to be in reverse order, but this isn't the case.
                // UpdatePanels instantiate their templates in their OnInit, so a child
                // UpdatePanel only exists in the control tree after the parent has been 
                // initialized.
 
                HtmlForm form = _owner.Page.Form; 

                for (int i = 0; i < _allUpdatePanels.Count; i++) { 
                    UpdatePanel panel = _allUpdatePanels[i];

                    // Check whether the panel thinks it wants to update. Possible reasons
                    // a panel might be updating: 
                    // - Postback data indicates the postback came from within the panel
                    // - Explicit call to panel.Update() 
                    // - Panel UpdateMode set to Always 
                    // - Trigger fired (not yet implemented)
 
                    bool panelUpdatedByClient =
                        _updatePanelRequiresUpdate != null &&
                        String.Equals(panel.UniqueID, _updatePanelRequiresUpdate, StringComparison.Ordinal);
                    bool requiresUpdate = panelUpdatedByClient || panel.RequiresUpdate; 

                    // Check and see if a parent panel will take update this panel, whether 
                    // this panel wants to update or not. If so, then this panel doesn't need 
                    // to be in update mode since it will get included in the rendering
                    // by its parent anyway. 
                    // If this parent doesn't want to update then we don't need to do any
                    // additional checks because whether it renders depends entirely on
                    // whether the parent wants to render.
                    Control parent = panel.Parent; 
                    while (parent != form) {
                        UpdatePanel parentUpdatePanel = parent as UpdatePanel; 
                        if ((parentUpdatePanel != null) && 
                            (_updatePanelsToRefresh.Contains(parentUpdatePanel) || _childUpdatePanelsToRefresh.Contains(parentUpdatePanel))) {
                            // This panel is inside another UpdatePanel that is being 
                            // rendered, so it should render in normal mode.
                            requiresUpdate = false;
                            _childUpdatePanelsToRefresh.Add(panel);
                            break; 
                        }
 
                        parent = parent.Parent; 

                        if (parent == null) { 
                            // This UpdatePanel was not inside an HtmlForm
                            // This really shouldn't happen, because the UpdatePanel would have thrown
                            // an exception on the initial GET request that it should be inside a form,
                            // so we'll just ignore it now... 
                            requiresUpdate = false;
                            break; 
                        } 
                    }
 
                    if (requiresUpdate) {
                        panel.SetAsyncPostBackMode(true);
                        _updatePanelsToRefresh.Add(panel);
                    } 
                    else {
                        panel.SetAsyncPostBackMode(false); 
                    } 
                }
            } 
        }

        public void RegisterAsyncPostBackControl(Control control) {
            Exception ex = GetControlRegistrationException(control); 
            if (ex != null) {
                throw ex; 
            } 
            if (_postBackControls != null && _postBackControls.Contains(control)) {
                throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, AtlasWeb.ScriptManager_CannotRegisterBothPostBacks, control.ID)); 
            }
            if (_asyncPostBackControls == null) {
                _asyncPostBackControls = new List();
            } 
            // It is acceptable to register the same control twice since the same
            // control might be referred to by more than one trigger. 
            if (!_asyncPostBackControls.Contains(control)) { 
                _asyncPostBackControls.Add(control);
            } 
        }

        public void RegisterDataItem(Control control, string dataItem, bool isJsonSerialized) {
            if (control == null) { 
                throw new ArgumentNullException("control");
            } 
            if (!_owner.IsInAsyncPostBack) { 
                throw new InvalidOperationException(AtlasWeb.PageRequestManager_RegisterDataItemInNonAsyncRequest);
            } 
            if (_scriptDataItems == null) {
                _scriptDataItems = new ScriptDataItemCollection();
            }
            else { 
                if (_scriptDataItems.ContainsControl(control)) {
                    throw new ArgumentException( 
                        String.Format( 
                            CultureInfo.InvariantCulture,
                            AtlasWeb.PageRequestManager_RegisterDataItemTwice, 
                            control.ID),
                        "control");
                }
            } 
            _scriptDataItems.Add(new ScriptDataItem(control, dataItem, isJsonSerialized));
        } 
 
        private void RegisterFocusScript() {
            if (ClientSupportsFocus && !_requireFocusScript) { 
                _requireFocusScript = true;
            }
        }
 
        public void RegisterPostBackControl(Control control) {
            Exception ex = GetControlRegistrationException(control); 
            if (ex != null) { 
                throw ex;
            } 
            if (_asyncPostBackControls != null && _asyncPostBackControls.Contains(control)) {
                throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, AtlasWeb.ScriptManager_CannotRegisterBothPostBacks, control.ID));
            }
            if (_postBackControls == null) { 
                _postBackControls = new List();
            } 
            // It is acceptable to register the same control twice since the same 
            // control might be referred to by more than one trigger.
            if (!_postBackControls.Contains(control)) { 
                _postBackControls.Add(control);
            }
        }
 
        internal void RegisterUpdatePanel(UpdatePanel updatePanel) {
            Debug.Assert(updatePanel != null); 
            if (_allUpdatePanels == null) { 
                _allUpdatePanels = new List();
            } 
            Debug.Assert(!_allUpdatePanels.Contains(updatePanel),
                String.Format(CultureInfo.InvariantCulture, "The UpdatePanel with ID '{0}' has already been registered with the ScriptManager.", updatePanel.ID));
            _allUpdatePanels.Add(updatePanel);
 
            if (_panelsInitialized) {
                // Do catch-up for panels that may have been added later in 
                // the lifecycle during an async post. 
                Debug.Assert(_owner.IsInAsyncPostBack, "Catch-up initialization should only be done in async posts.");
                updatePanel.Initialize(); 
            }
        }

        internal void Render(HtmlTextWriter writer) { 
            if (!((IControl)_owner).DesignMode && !_owner.IsInAsyncPostBack && _owner.SupportsPartialRendering) {
                _owner.IPage.VerifyRenderingInServerForm(_owner); 
                RenderPageRequestManagerScript(writer); 
            }
        } 

        private void RenderFormCallback(HtmlTextWriter writer, Control containerControl) {

            Debug.Assert(_updatePanelWriter != null, "_updatePanelWriter should be set by RenderPageCallback before RenderFormCallback is called."); 

            ParserStringWriter parserWriter = writer.InnerWriter as ParserStringWriter; 
            // Disable parsing while rendering UpdatePanels 
            parserWriter.ParseWrites = false;
 

            // Suppress rendering of default content; instead just render out
            // update panels
            if (_updatePanelsToRefresh != null) { 
                foreach (UpdatePanel panel in _updatePanelsToRefresh) {
                    if (panel.Visible) { 
                        // Write UpdatePanels to the response's writer; the writer passed in is a 
                        // dummy parserWriter.  It will contain hidden fields that are written to
                        // the response's writer later in RenderPageCallback. 
                        panel.RenderControl(_updatePanelWriter);
                    }
                }
            } 

            IPage page = _owner.IPage; 
            if (page.EnableEventValidation) { 
                // If the page has event validation turned on, we need to run through
                // the render logic for the rest of the page as well. However, the 
                // rendering is essentially ignored.
                // UpdatePanels that were already rendered above do not re-render by checking
                // a flag whether they already rendered.
 
                //
 
 

 

                // DevDiv 55447: Do not use Response.Flush and a NullStream to prevent Response.Writes
                // from being written to the output stream, as calling Response.Flush causes headers to
                // be written. This prevents cookies from being issued after this, for example. 
                // Instead, use a NullWriter that ignores Writes. We can change the writer used by HttpResponse
                // using the internal SwitchWriter method. 
                // We must do this since data written via Response.Write will make the partial update 
                // response invalid.
 
                TextWriter oldWriter = null;
                bool writerSwitched = false;
                try {
                    // beginning of possible direct Response.Writes 
                    oldWriter = page.Response.SwitchWriter(TextWriter.Null);
                    // if we cant switch the writer for some reason we need to know not to switch it back again in the finally block 
                    // writerSwitched will be false 
                    writerSwitched = true;
 
                    // nullHtmlWriter captures any writes by controls to the textwriter they are passed.
                    // Note that we could possibly just let null TextWriter we switched catch this data, but this
                    // is more efficient.
                    HtmlTextWriter nullHtmlWriter = new HtmlTextWriter(TextWriter.Null); 
                    foreach (Control control in containerControl.Controls) {
                        control.RenderControl(nullHtmlWriter); 
                    } 
                }
                finally { 
                    // end of possible direct Response.Writes
                    if (writerSwitched) {
                        page.Response.SwitchWriter(oldWriter);
                    } 
                }
            } 
 
            // Re-enable parsing now that the form is done rendering its content
            parserWriter.ParseWrites = true; 
        }

        private void RenderPageCallback(HtmlTextWriter writer, Control pageControl) {
            ProcessUpdatePanels(); 

            // Although we could use the pageControl parameter it's hard to write 
            // unit tests for it. Instead we just use our own page, which is the 
            // same instance anyway (but easier to test with).
 
            HttpResponseBase response = _owner.IPage.Response;

            response.ContentType = "text/plain";
            response.Cache.SetNoServerCaching(); 

            // Render the form. It will render its tag, hidden fields, etc. 
            // and then call our render method delegate, which will in turn render 
            // all the UpdatePanels
            IHtmlForm formControl = _owner.IPage.Form; 
            formControl.SetRenderMethodDelegate(RenderFormCallback);

            // Let updatePanels write directly to Response
            _updatePanelWriter = writer; 

            // Let form header/footer write to a parser 
            ParserStringWriter parserWriter = new ParserStringWriter(); 
            ParserHtmlTextWriter formWriter = new ParserHtmlTextWriter(parserWriter);
            parserWriter.ParseWrites = true; 
            formControl.RenderControl(formWriter);
            parserWriter.ParseWrites = false;

            // Write out built-in ASP.NET hidden fields 
            // Hidden fields registered by partial-rendering compatible controls will be
            // rendered by ProcessScriptRegistration(). 
            foreach (KeyValuePair hiddenField in parserWriter.HiddenFields) { 
                if (ControlUtil.IsBuiltInHiddenField(hiddenField.Key)) {
                    EncodeString(writer, HiddenFieldToken, hiddenField.Key, hiddenField.Value); 
                }
            }

            // Write out PageRequestManager settings that can change during an async postback. 
            // This is required for dynamic UpdatePanels since the list of panels could
            // change. 
            EncodeString(writer, AsyncPostBackControlIDsToken, String.Empty, GetAsyncPostBackControlIDs(false)); 
            EncodeString(writer, PostBackControlIDsToken, String.Empty, GetPostBackControlIDs(false));
            EncodeString(writer, UpdatePanelIDsToken, String.Empty, GetAllUpdatePanelIDs()); 
            EncodeString(writer, ChildUpdatePanelIDsToken, String.Empty, GetChildUpdatePanelIDs());
            EncodeString(writer, UpdatePanelsToRefreshToken, String.Empty, GetRefreshingUpdatePanelIDs());
            EncodeString(writer, AsyncPostBackTimeoutToken, String.Empty, _owner.AsyncPostBackTimeout.ToString(CultureInfo.InvariantCulture));
            if (formWriter.FormAction != null) { 
                EncodeString(writer, FormActionToken, String.Empty, formWriter.FormAction);
            } 
            if (_owner.IPage.Header != null) { 
                string pageTitle = _owner.IPage.Title;
                if (!String.IsNullOrEmpty(pageTitle)) { 
                    EncodeString(writer, PageTitleToken, String.Empty, pageTitle);
                }
            }
            RenderDataItems(writer); 

            ProcessScriptRegistration(writer); 
 
            // We process the focus after regular script registrations to
            // make sure that if it ends up including some script that it 
            // executes last.
            ProcessFocus(writer);
        }
 
        private void RenderDataItems(HtmlTextWriter writer) {
            if (_scriptDataItems != null) { 
                foreach (ScriptDataItem dataItem in _scriptDataItems) { 
                    EncodeString(
                        writer, 
                        dataItem.IsJsonSerialized ? DataItemJsonToken : DataItemToken,
                        dataItem.Control.ClientID,
                        dataItem.DataItem);
                } 
            }
        } 
 
        internal void RenderPageRequestManagerScript(HtmlTextWriter writer) {
            // 



 

 
            // Script format: 
            // 
 
            // Writing directly to the writer is more performant than building 
            // up a big string with formatting and then writing it out later.
 
            writer.Write(@" 
");
        }

        private static void RenderUpdatePanelIDsFromList(HtmlTextWriter writer, List list) { 
            // Writing directly to the writer is more performant than building
            // up a big string with formatting and then writing it out later. 
            if (list != null && list.Count > 0) { 
                bool first = true;
                for (int i = 0; i < list.Count; i++) { 
                    if (!list[i].Visible) {
                        // If the panel isn't visible, the client doesn't need to know about it
                        continue;
                    } 
                    if (!first) {
                        writer.Write(','); 
                    } 
                    first = false;
                    writer.Write('\''); 

                    // We send down the UniqueID instead of the ClientID because
                    // we need both versions on the client. You can convert from
                    // UniqueID to ClientID, but not back. 

                    // We also send down a bool indicating whether the children of 
                    // the panel count as triggers or not. 
                    writer.Write(list[i].ChildrenAsTriggers ? 't' : 'f');
                    writer.Write(list[i].UniqueID); 

                    writer.Write('\'');
                }
            } 
        }
 
        public void SetFocus(Control control) { 
            // We always call the real Page's method at least to do parameter validation
            _owner.IPage.SetFocus(control); 

            // If it's not async, just let the page do whatever it wants. If we are
            // in an async post, we need to keep track of what to focus later on.
            if (_owner.IsInAsyncPostBack) { 
                _focusedControl = control;
                _focusedControlID = null; 
                RegisterFocusScript(); 
            }
        } 

        public void SetFocus(string clientID) {
            // We always call the real Page's method at least to do parameter validation
            _owner.IPage.SetFocus(clientID); 
            SetFocusInternal(clientID);
        } 
 
        internal void SetFocusInternal(string clientID) {
            // If it's not async, just let the page do whatever it wants. If we are 
            // in an async post, we need to keep track of what to focus later on.
            if (_owner.IsInAsyncPostBack) {
                _focusedControlID = clientID.Trim();
                _focusedControl = null; 
                RegisterFocusScript();
            } 
        } 

        internal void UnregisterUpdatePanel(UpdatePanel updatePanel) { 
            Debug.Assert(updatePanel != null);
            if ((_allUpdatePanels == null) || !_allUpdatePanels.Contains(updatePanel)) {
                throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, AtlasWeb.ScriptManager_UpdatePanelNotRegistered, updatePanel.ID), "updatePanel");
            } 
            _allUpdatePanels.Remove(updatePanel);
        } 
 
        // Specialized parser StringWriter that can detect when ASP.NET renders
        // hidden field tags. It strips them from the rendering, and 
        // they can later be retrieved via properties. It only parses while
        // ParseWrites is set to true.
        private sealed class ParserStringWriter : StringWriter {
            private enum ParserState { 
                Ready = 0,
                ReadHiddenFieldNameValue = 1, 
                ReadHiddenFieldIdAttribute = 2, 
                ReadHiddenFieldIdValue = 3,
                ReadHiddenFieldValueAttribute = 4, 
                ReadHiddenFieldValueValue = 5,
            }

            private bool _parseWrites; 

            private List _pendingWrites = new List(); 
 
            private ParserState _parserState = ParserState.Ready;
            private bool _secondTry; // Indicates that we might be accepting a 2nd write for the same parser state 
            private string _proposedHiddenFieldName = String.Empty;
            private string _matchingHiddenFieldName = String.Empty;
            private StringBuilder _proposedHiddenFieldValue = new StringBuilder();
 
            private Dictionary _hiddenFields = new Dictionary();
 
            public ParserStringWriter() 
                : base(CultureInfo.CurrentCulture) {
            } 

            // Gets the name/value pairs for hidden fields parsed from the content.
            public IDictionary HiddenFields {
                get { 
                    return _hiddenFields;
                } 
            } 

            // Indicates whether calls to Write(string) and WriteLine(string) 
            // should be parsed for specific content.
            public bool ParseWrites {
                get {
                    return _parseWrites; 
                }
                set { 
                    _parseWrites = value; 
                }
            } 

            private void FlushPendingWrites() {
                if (_pendingWrites.Count > 0) {
                    foreach (string pendingWrite in _pendingWrites) { 
                        base.Write(pendingWrite);
                    } 
                    _pendingWrites.Clear(); 
                }
            } 

            private void ParseString(string s) {
                switch (_parserState) {
                    case ParserState.Ready: 
                        if (s == "") {
                            _proposedHiddenFieldValue.Append(s); 
                        } 
                        else {
                            // If we get here that means we have a complete hidden field 
                            _pendingWrites.Clear();
                            _hiddenFields.Add(_proposedHiddenFieldName, _proposedHiddenFieldValue.ToString());
                            _proposedHiddenFieldName = String.Empty;
                            _matchingHiddenFieldName = String.Empty; 
                            _proposedHiddenFieldValue = new StringBuilder();
                            _parserState = ParserState.Ready; 
                        } 
                        break;
 
                    default:
                        _secondTry = false;
                        FlushPendingWrites();
                        base.Write(s); 
                        break;
                } 
            } 

            public override void Write(string s) { 
                if (!ParseWrites) {
                    base.Write(s);
                    return;
                } 

                ParseString(s); 
            } 

            public override void WriteLine(string value) { 
                if (!ParseWrites) {
                    base.WriteLine(value);
                    return;
                } 

                // For simplicity's sake, we turn parsed WriteLines into two 
                // calls to our parser. 
                ParseString(value);
                ParseString(NewLine); 
            }
        }

        private sealed class ParserHtmlTextWriter : HtmlTextWriter { 
            private bool _writingForm;
            private string _formAction; 
 
            public string FormAction {
                get { 
                    return _formAction;
                }
            }
 

            public ParserHtmlTextWriter(TextWriter writer) 
                : base(writer) { 
            }
 

            public override void WriteBeginTag(string tagName) {
                base.WriteBeginTag(tagName);
 
                //
                _writingForm = (tagName == "form"); 
            } 

            public override void WriteAttribute(string name, string value, bool fEncode) { 
                base.WriteAttribute(name, value, fEncode);

                //
                if (_writingForm) { 
                    if (name == "action") {
                        _formAction = value; 
                    } 
                }
            } 
        }

        private sealed class ScriptDataItem {
            private Control _control; 
            private string _dataItem;
            private bool _isJsonSerialized; 
 
            public ScriptDataItem(Control control, string dataItem, bool isJsonSerialized) {
                _control = control; 
                _dataItem = (dataItem == null) ? String.Empty : dataItem;
                _isJsonSerialized = isJsonSerialized;
            }
 
            public Control Control {
                get { 
                    return _control; 
                }
            } 

            public string DataItem {
                get {
                    return _dataItem; 
                }
            } 
 
            public bool IsJsonSerialized {
                get { 
                    return _isJsonSerialized;
                }
            }
        } 

        private sealed class ScriptDataItemCollection : List { 
            public bool ContainsControl(Control control) { 
                foreach (ScriptDataItem dataItem in this) {
                    if (dataItem.Control == control) { 
                        return true;
                    }
                }
                return false; 
            }
        } 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

namespace System.Web.UI { 
    using System; 
    using System.Collections;
    using System.Collections.Generic; 
    using System.Collections.Specialized;
    using System.Diagnostics;
    using System.Globalization;
    using System.IO; 
    using System.Security;
    using System.Text; 
    using System.Web; 
    using System.Web.Configuration;
    using System.Web.UI; 
    using System.Web.UI.HtmlControls;
    using System.Web.Resources;
    using System.Web.Script.Serialization;
    using System.Reflection; 
    using System.Security.Permissions;
 
    internal sealed class PageRequestManager { 

        // Type tokens for partial rendering format 
        internal const string PageRedirectToken = "pageRedirect";
        internal const string HiddenFieldToken = "hiddenField";
        private const string AsyncPostBackControlIDsToken = "asyncPostBackControlIDs";
        private const string PostBackControlIDsToken = "postBackControlIDs"; 
        private const string UpdatePanelIDsToken = "updatePanelIDs";
        private const string AsyncPostBackTimeoutToken = "asyncPostBackTimeout"; 
        private const string ChildUpdatePanelIDsToken = "childUpdatePanelIDs"; 
        private const string UpdatePanelsToRefreshToken = "panelsToRefreshIDs";
        private const string FormActionToken = "formAction"; 
        private const string DataItemToken = "dataItem";
        private const string DataItemJsonToken = "dataItemJson";
        internal const string ArrayDeclarationToken = "arrayDeclaration";
        internal const string ExpandoToken = "expando"; 
        internal const string OnSubmitToken = "onSubmit";
        internal const string ScriptBlockToken = "scriptBlock"; 
        internal const string ScriptStartupBlockToken = "scriptStartupBlock"; 
        internal const string ScriptDisposeToken = "scriptDispose";
        internal const string ErrorToken = "error"; 
        internal const string AsyncPostBackErrorKey = "System.Web.UI.PageRequestManager:AsyncPostBackError";
        internal const string AsyncPostBackErrorMessageKey = "System.Web.UI.PageRequestManager:AsyncPostBackErrorMessage";
        internal const string AsyncPostBackErrorHttpCodeKey = "System.Web.UI.PageRequestManager:AsyncPostBackErrorHttpCode";
        private const string PageTitleToken = "pageTitle"; 
        private const string FocusToken = "focus";
        private const string AsyncPostFormField = "__ASYNCPOST"; 
 
        private const char LengthEncodeDelimiter = '|';
        private static readonly Version MinimumW3CDomVersion = new Version(1, 0); 
        private static readonly Version MinimumEcmaScriptVersion = new Version(1, 0);

        private ScriptManager _owner;
 
        private List _allUpdatePanels;
        private List _updatePanelsToRefresh; 
        private List _childUpdatePanelsToRefresh; 
        private List _asyncPostBackControls;
        private List _postBackControls; 
        private ScriptDataItemCollection _scriptDataItems;
        private string _updatePanelRequiresUpdate;
        private HtmlTextWriter _updatePanelWriter;
        private bool _panelsInitialized; 
        private string _asyncPostBackSourceElementID;
 
        // Stolen from Whidbey Page.cs for focus support 
        private static readonly Version FocusMinimumEcmaVersion = new Version("1.4");
        private static readonly Version FocusMinimumJScriptVersion = new Version("3.0"); 
        private string _focusedControlID;
        private Control _focusedControl;
        private bool _requireFocusScript;
 
        public PageRequestManager(ScriptManager owner) {
            Debug.Assert(owner != null); 
            _owner = owner; 
        }
 

        public string AsyncPostBackSourceElementID {
            get {
                if (_asyncPostBackSourceElementID == null) { 
                    return String.Empty;
                } 
                return _asyncPostBackSourceElementID; 
            }
        } 

        // Stolen from Whidbey Page.cs
        private bool ClientSupportsFocus {
            get { 
                HttpBrowserCapabilitiesBase browser = _owner.IPage.Request.Browser;
                return 
                    (browser.EcmaScriptVersion >= FocusMinimumEcmaVersion) || 
                    (browser.JScriptVersion >= FocusMinimumJScriptVersion);
            } 
        }

        private bool EnableLegacyRendering {
            get { 
                return _owner.EnableLegacyRendering;
            } 
        } 

        [SecurityCritical()] 
        [SecurityTreatAsSafe()]
        private bool CustomErrorsSectionHasRedirect(int httpCode) {
            bool hasRedirect = (_owner.CustomErrorsSection.DefaultRedirect != null);
            if (!hasRedirect) { 
                if (_owner.CustomErrorsSection.Errors != null) {
                    foreach (CustomError error in _owner.CustomErrorsSection.Errors) { 
                        if (error.StatusCode == httpCode) { 
                            hasRedirect = true;
                            break; 
                        }
                    }
                }
            } 
            return hasRedirect;
        } 
 
        // Optimized version of EncodeString that writes directly to a writer. This
        // eliminates the need to create several copies of the same string as well 
        // as a StringBuilder.
        internal static void EncodeString(TextWriter writer, string type, string id, string content) {
            Debug.Assert(!String.IsNullOrEmpty(type), "Type should always be specified");
            if (id == null) { 
                id = String.Empty;
            } 
            if (content == null) { 
                content = String.Empty;
            } 
            Debug.Assert(type.IndexOf(LengthEncodeDelimiter) == -1, "Should not be a " + LengthEncodeDelimiter + " in type");
            Debug.Assert(id.IndexOf(LengthEncodeDelimiter) == -1, "Should not be a " + LengthEncodeDelimiter + " in id");

            // len|type|id|content| 
            //             -------   len
 
            writer.Write(content.Length.ToString(CultureInfo.InvariantCulture)); 
            writer.Write(LengthEncodeDelimiter);
            writer.Write(type); 
            writer.Write(LengthEncodeDelimiter);
            writer.Write(id);
            writer.Write(LengthEncodeDelimiter);
            // DevDiv 75383: We used to escape null characters from the content, but this had a non trivial hit on perf 
            // They were escaped because XMLHttpRequest in IE truncates content after a null character.
            // However, when HTML contains a null character, subsequent content is truncated anyway, so the value of escaping nulls 
            // in the first place is not clear and it was decided it is not worth the perf hit. 
            writer.Write(content);
            writer.Write(LengthEncodeDelimiter); 
        }

        private string GetAllUpdatePanelIDs() {
            return GetUpdatePanelIDsFromList(_allUpdatePanels, true); 
        }
 
        private string GetAsyncPostBackControlIDs(bool includeQuotes) { 
            return GetControlIDsFromList(_asyncPostBackControls, includeQuotes);
        } 

        private string GetChildUpdatePanelIDs() {
            return GetUpdatePanelIDsFromList(_childUpdatePanelsToRefresh, false);
        } 

        private static string GetControlIDsFromList(List list, bool includeQuotes) { 
            if (list != null && list.Count > 0) { 
                StringBuilder asyncPostBackControlIDs = new StringBuilder();
                bool first = true; 
                for (int i = 0; i < list.Count; i++) {
                    if (!list[i].Visible) {
                        // If the panel isn't visible, the client doesn't need to know about it
                        continue; 
                    }
                    if (!first) { 
                        asyncPostBackControlIDs.Append(','); 
                    }
                    first = false; 
                    if (includeQuotes) {
                        asyncPostBackControlIDs.Append('\'');
                    }
                    asyncPostBackControlIDs.Append(list[i].UniqueID); 
                    if (includeQuotes) {
                        asyncPostBackControlIDs.Append('\''); 
                    } 
                }
                return asyncPostBackControlIDs.ToString(); 
            }
            return String.Empty;
        }
 
        private static Exception GetControlRegistrationException(Control control) {
            // DevDiv Bugs 145573: It is ok to register the Page as an async/postback control 
            if (control == null) { 
                return new ArgumentNullException("control");
            } 
            if (!(control is INamingContainer) &&
                !(control is IPostBackDataHandler) &&
                !(control is IPostBackEventHandler)) {
                return new ArgumentException(String.Format(CultureInfo.InvariantCulture, AtlasWeb.ScriptManager_InvalidControlRegistration, control.ID)); 
            }
            return null; 
        } 

        // This code is roughly stolen from HttpException.GetHttpCodeForException() 
        private static int GetHttpCodeForException(Exception e) {
            HttpException he = e as HttpException;
            if (he != null) {
                return he.GetHttpCode(); 
            }
            else if (e is UnauthorizedAccessException) { 
                return 401; 
            }
            else if (e is PathTooLongException) { 
                return 414;
            }

            // If there is an inner exception, try to get the code from it 
            if (e.InnerException != null)
                return GetHttpCodeForException(e.InnerException); 
 
            // If all else fails, use 500
            return 500; 
        }

        private string GetPostBackControlIDs(bool includeQuotes) {
            return GetControlIDsFromList(_postBackControls, includeQuotes); 
        }
 
        private string GetRefreshingUpdatePanelIDs() { 
            return GetUpdatePanelIDsFromList(_updatePanelsToRefresh, false);
        } 

        private static string GetUpdatePanelIDsFromList(List list, bool includeChildrenAsTriggersPrefix) {
            if (list != null && list.Count > 0) {
                StringBuilder updatePanelIDs = new StringBuilder(); 
                bool first = true;
                for (int i = 0; i < list.Count; i++) { 
                    if (!list[i].Visible) { 
                        // If the panel isn't visible, the client doesn't need to know about it
                        continue; 
                    }
                    if (!first) {
                        updatePanelIDs.Append(',');
                    } 
                    first = false;
                    // We send down the UniqueID instead of the ClientID because 
                    // we need both versions on the client. You can convert from 
                    // UniqueID to ClientID, but not back.
 
                    // We also send down a bool indicating whether the children of
                    // the panel count as triggers or not.
                    if (includeChildrenAsTriggersPrefix) {
                        updatePanelIDs.Append(list[i].ChildrenAsTriggers ? 't' : 'f'); 
                    }
                    updatePanelIDs.Append(list[i].UniqueID); 
                } 
                return updatePanelIDs.ToString();
            } 
            return String.Empty;
        }

        internal static bool IsAsyncPostBackRequest(HttpRequestBase request) { 
            // Detect the header for async postbacks. A header can appear
            // multiple times, and each header entry can contain a comma-separated 
            // list of values. ASP.NET doesn't split the comma-separated values for 
            // us so we have to do it.
 
            // We used to use the Pragma header but some browsers, such as Opera,
            // do not support sending it through XMLHttpRequest. Instead we use a
            // custom header, X-MicrosoftAjax.
            string[] headerValues = request.Headers.GetValues("X-MicrosoftAjax"); 
            if (headerValues != null) {
                for (int i = 0; i < headerValues.Length; i++) { 
                    string[] headerContents = headerValues[i].Split(','); 
                    for (int j = 0; j < headerContents.Length; j++) {
                        if (headerContents[j].Trim() == "Delta=true") { 
                            return true;
                        }
                    }
                } 
            }
            // DevDiv Bugs 188713: X-MicrosoftAjax header is stripped by some firewalls 
            string asyncPost = request.Form[AsyncPostFormField]; 
            return !String.IsNullOrEmpty(asyncPost) &&
                (asyncPost.Trim() == "true"); 
        }

        internal void LoadPostData(string postDataKey, NameValueCollection postCollection) {
            // Check if the async postback was caused by a specific panel, and if so, force 
            // that panel to update, regardless of whether it had any explicit triggers, etc.
            // If the post back data starts with the ScriptManager's UniqueID that means the 
            // async postback was caused by a control outside of an UpdatePanel, and the rest 
            // of the string is the UniqueID of that control.
            string postBackSourceInfo = postCollection[postDataKey]; 
            if (postBackSourceInfo != null) {
                string postBackTarget; // The target of the postback - either the ScriptManager or an UpdatePanel

                int indexOfPipe = postBackSourceInfo.IndexOf('|'); 
                if (indexOfPipe != -1) {
                    // We have a target and source element 
                    postBackTarget = postBackSourceInfo.Substring(0, indexOfPipe); 
                    _asyncPostBackSourceElementID = postBackSourceInfo.Substring(indexOfPipe + 1);
                } 
                else {
                    // We only have a target
                    postBackTarget = postBackSourceInfo;
                    _asyncPostBackSourceElementID = String.Empty; 
                }
 
                if (postBackTarget != _owner.UniqueID) { 
                    _updatePanelRequiresUpdate = postBackTarget;
                } 
            }

            // Initialize all UpdatePanels (and their triggers, specifically) so that
            // they can hook events, etc. before other controls can process their 
            // own post data.
            // LoadPostData on ScriptManager only gets called during async posts, and 
            // is guaranteed to be called before any other controls have a chance to 
            // process their post data.
            // During regular posts the UpdatePanel initializes itself in OnLoad. 
            if ((_allUpdatePanels != null) && (_allUpdatePanels.Count != 0)) {
                foreach (UpdatePanel panel in _allUpdatePanels) {
                    panel.Initialize();
                } 
            }
 
            _panelsInitialized = true; 
        }
 
        internal void OnInit() {
            // Check if the browser supports partial rendering. We only do the check
            // if the user hasn't already forced the feature to be on or off explicitly.
            if (_owner.EnablePartialRendering && !_owner._supportsPartialRenderingSetByUser) { 
                HttpBrowserCapabilitiesBase browser = _owner.IPage.Request.Browser;
                // There is no browser cap that directly tells us whether the browser 
                // supports XmlHttpRequest so we use the next best capability, which is 
                // the SupportsCallback property.
                // Checking the other properties helps exclude agents such as crawlers. 
                bool supportsPartialRendering =
                    (browser.W3CDomVersion >= MinimumW3CDomVersion) &&
                    (browser.EcmaScriptVersion >= MinimumEcmaScriptVersion) &&
                    browser.SupportsCallback; 
                if (supportsPartialRendering) {
                    // If we still think we want to support it, now do a more expensive 
                    // check for XHTML legacy rendering support. 
                    supportsPartialRendering = !EnableLegacyRendering;
                } 
                _owner.SupportsPartialRendering = supportsPartialRendering;
            }

            if (_owner.IsInAsyncPostBack) { 
                _owner.IPage.Error += OnPageError;
            } 
        } 

        private void OnPageError(object sender, EventArgs e) { 
            Exception ex = _owner.IPage.Server.GetLastError();
            _owner.OnAsyncPostBackError(new AsyncPostBackErrorEventArgs(ex));

            string errorMessage = _owner.AsyncPostBackErrorMessage; 
            if (String.IsNullOrEmpty(errorMessage) && !_owner.Control.Context.IsCustomErrorEnabled) {
                // Only use the exception's message if we're not doing custom errors 
                errorMessage = ex.Message; 
            }
 
            int httpCode = GetHttpCodeForException(ex);

            bool showAsyncErrorMessage = false;
 
            if (_owner.AllowCustomErrorsRedirect && _owner.Control.Context.IsCustomErrorEnabled) {
                // Figure out if there's going to be a redirect for this error 
                bool hasRedirect = CustomErrorsSectionHasRedirect(httpCode); 
                if (!hasRedirect) {
                    // If there's no redirect, we need to send back the error message 
                    showAsyncErrorMessage = true;
                }
                // If there was a redirect we do nothing since ASP.NET will automatically
                // redirect the user to the error page anyway. This way we don't have to 
                // worry about how to resolve the paths from config.
            } 
            else { 
                // If we're not going to use custom errors, just send back the error message
                showAsyncErrorMessage = true; 
            }

            if (showAsyncErrorMessage) {
                IDictionary items = _owner.Control.Context.Items; 
                items[AsyncPostBackErrorKey] = true;
                items[AsyncPostBackErrorMessageKey] = errorMessage; 
                items[AsyncPostBackErrorHttpCodeKey] = httpCode; 
            }
        } 

        internal void OnPreRender() {
            _owner.IPage.SetRenderMethodDelegate(RenderPageCallback);
        } 

        private void ProcessFocus(HtmlTextWriter writer) { 
            // Roughly stolen from Whidbey Page.cs 
            if (_requireFocusScript) {
                Debug.Assert(ClientSupportsFocus, "If ClientSupportsFocus is false then we never should have set _requireFocusScript to true."); 
                string focusedControlId = String.Empty;

                // Someone calling SetFocus(controlId) has the most precedent
                if (!String.IsNullOrEmpty(_focusedControlID)) { 
                    focusedControlId = _focusedControlID;
                } 
                else { 
                    if (_focusedControl != null && _focusedControl.Visible) {
                        focusedControlId = _focusedControl.ClientID; 
                    }
                }
                if (focusedControlId.Length > 0) {
                    // Register focus script library 
                    string focusResourceUrl = _owner.GetScriptResourceUrl("Focus.js", typeof(HtmlForm).Assembly);
                    EncodeString(writer, ScriptBlockToken, "ScriptPath", focusResourceUrl); 
 
                    // Send the target control ID to the client
                    EncodeString(writer, FocusToken, String.Empty, focusedControlId); 
                }
            }
        }
 
        private void ProcessScriptRegistration(HtmlTextWriter writer) {
            _owner.ScriptRegistration.RenderActiveArrayDeclarations(_updatePanelsToRefresh, writer); 
            _owner.ScriptRegistration.RenderActiveScripts(_updatePanelsToRefresh, writer); 
            _owner.ScriptRegistration.RenderActiveSubmitStatements(_updatePanelsToRefresh, writer);
            _owner.ScriptRegistration.RenderActiveExpandos(_updatePanelsToRefresh, writer); 
            _owner.ScriptRegistration.RenderActiveHiddenFields(_updatePanelsToRefresh, writer);
            _owner.ScriptRegistration.RenderActiveScriptDisposes(_updatePanelsToRefresh, writer);
        }
 
        private void ProcessUpdatePanels() {
            Debug.Assert(_owner.IsInAsyncPostBack); 
            Debug.Assert(_updatePanelsToRefresh == null); 

            if (_allUpdatePanels != null) { 
                _updatePanelsToRefresh = new List(_allUpdatePanels.Count);
                _childUpdatePanelsToRefresh = new List(_allUpdatePanels.Count);

                // Process the UpdatePanels to determine which are to be set in 
                // partial rendering mode.
 
                // We need to process the list such that parent UpdatePanels are 
                // evaluated first. A child UpdatePanel inside a parent that is being
                // updated should not be considered in partial rendering mode. 
                // Ordinarily child controls get initialized first before their parents
                // so you'd expect the list to be in reverse order, but this isn't the case.
                // UpdatePanels instantiate their templates in their OnInit, so a child
                // UpdatePanel only exists in the control tree after the parent has been 
                // initialized.
 
                HtmlForm form = _owner.Page.Form; 

                for (int i = 0; i < _allUpdatePanels.Count; i++) { 
                    UpdatePanel panel = _allUpdatePanels[i];

                    // Check whether the panel thinks it wants to update. Possible reasons
                    // a panel might be updating: 
                    // - Postback data indicates the postback came from within the panel
                    // - Explicit call to panel.Update() 
                    // - Panel UpdateMode set to Always 
                    // - Trigger fired (not yet implemented)
 
                    bool panelUpdatedByClient =
                        _updatePanelRequiresUpdate != null &&
                        String.Equals(panel.UniqueID, _updatePanelRequiresUpdate, StringComparison.Ordinal);
                    bool requiresUpdate = panelUpdatedByClient || panel.RequiresUpdate; 

                    // Check and see if a parent panel will take update this panel, whether 
                    // this panel wants to update or not. If so, then this panel doesn't need 
                    // to be in update mode since it will get included in the rendering
                    // by its parent anyway. 
                    // If this parent doesn't want to update then we don't need to do any
                    // additional checks because whether it renders depends entirely on
                    // whether the parent wants to render.
                    Control parent = panel.Parent; 
                    while (parent != form) {
                        UpdatePanel parentUpdatePanel = parent as UpdatePanel; 
                        if ((parentUpdatePanel != null) && 
                            (_updatePanelsToRefresh.Contains(parentUpdatePanel) || _childUpdatePanelsToRefresh.Contains(parentUpdatePanel))) {
                            // This panel is inside another UpdatePanel that is being 
                            // rendered, so it should render in normal mode.
                            requiresUpdate = false;
                            _childUpdatePanelsToRefresh.Add(panel);
                            break; 
                        }
 
                        parent = parent.Parent; 

                        if (parent == null) { 
                            // This UpdatePanel was not inside an HtmlForm
                            // This really shouldn't happen, because the UpdatePanel would have thrown
                            // an exception on the initial GET request that it should be inside a form,
                            // so we'll just ignore it now... 
                            requiresUpdate = false;
                            break; 
                        } 
                    }
 
                    if (requiresUpdate) {
                        panel.SetAsyncPostBackMode(true);
                        _updatePanelsToRefresh.Add(panel);
                    } 
                    else {
                        panel.SetAsyncPostBackMode(false); 
                    } 
                }
            } 
        }

        public void RegisterAsyncPostBackControl(Control control) {
            Exception ex = GetControlRegistrationException(control); 
            if (ex != null) {
                throw ex; 
            } 
            if (_postBackControls != null && _postBackControls.Contains(control)) {
                throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, AtlasWeb.ScriptManager_CannotRegisterBothPostBacks, control.ID)); 
            }
            if (_asyncPostBackControls == null) {
                _asyncPostBackControls = new List();
            } 
            // It is acceptable to register the same control twice since the same
            // control might be referred to by more than one trigger. 
            if (!_asyncPostBackControls.Contains(control)) { 
                _asyncPostBackControls.Add(control);
            } 
        }

        public void RegisterDataItem(Control control, string dataItem, bool isJsonSerialized) {
            if (control == null) { 
                throw new ArgumentNullException("control");
            } 
            if (!_owner.IsInAsyncPostBack) { 
                throw new InvalidOperationException(AtlasWeb.PageRequestManager_RegisterDataItemInNonAsyncRequest);
            } 
            if (_scriptDataItems == null) {
                _scriptDataItems = new ScriptDataItemCollection();
            }
            else { 
                if (_scriptDataItems.ContainsControl(control)) {
                    throw new ArgumentException( 
                        String.Format( 
                            CultureInfo.InvariantCulture,
                            AtlasWeb.PageRequestManager_RegisterDataItemTwice, 
                            control.ID),
                        "control");
                }
            } 
            _scriptDataItems.Add(new ScriptDataItem(control, dataItem, isJsonSerialized));
        } 
 
        private void RegisterFocusScript() {
            if (ClientSupportsFocus && !_requireFocusScript) { 
                _requireFocusScript = true;
            }
        }
 
        public void RegisterPostBackControl(Control control) {
            Exception ex = GetControlRegistrationException(control); 
            if (ex != null) { 
                throw ex;
            } 
            if (_asyncPostBackControls != null && _asyncPostBackControls.Contains(control)) {
                throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, AtlasWeb.ScriptManager_CannotRegisterBothPostBacks, control.ID));
            }
            if (_postBackControls == null) { 
                _postBackControls = new List();
            } 
            // It is acceptable to register the same control twice since the same 
            // control might be referred to by more than one trigger.
            if (!_postBackControls.Contains(control)) { 
                _postBackControls.Add(control);
            }
        }
 
        internal void RegisterUpdatePanel(UpdatePanel updatePanel) {
            Debug.Assert(updatePanel != null); 
            if (_allUpdatePanels == null) { 
                _allUpdatePanels = new List();
            } 
            Debug.Assert(!_allUpdatePanels.Contains(updatePanel),
                String.Format(CultureInfo.InvariantCulture, "The UpdatePanel with ID '{0}' has already been registered with the ScriptManager.", updatePanel.ID));
            _allUpdatePanels.Add(updatePanel);
 
            if (_panelsInitialized) {
                // Do catch-up for panels that may have been added later in 
                // the lifecycle during an async post. 
                Debug.Assert(_owner.IsInAsyncPostBack, "Catch-up initialization should only be done in async posts.");
                updatePanel.Initialize(); 
            }
        }

        internal void Render(HtmlTextWriter writer) { 
            if (!((IControl)_owner).DesignMode && !_owner.IsInAsyncPostBack && _owner.SupportsPartialRendering) {
                _owner.IPage.VerifyRenderingInServerForm(_owner); 
                RenderPageRequestManagerScript(writer); 
            }
        } 

        private void RenderFormCallback(HtmlTextWriter writer, Control containerControl) {

            Debug.Assert(_updatePanelWriter != null, "_updatePanelWriter should be set by RenderPageCallback before RenderFormCallback is called."); 

            ParserStringWriter parserWriter = writer.InnerWriter as ParserStringWriter; 
            // Disable parsing while rendering UpdatePanels 
            parserWriter.ParseWrites = false;
 

            // Suppress rendering of default content; instead just render out
            // update panels
            if (_updatePanelsToRefresh != null) { 
                foreach (UpdatePanel panel in _updatePanelsToRefresh) {
                    if (panel.Visible) { 
                        // Write UpdatePanels to the response's writer; the writer passed in is a 
                        // dummy parserWriter.  It will contain hidden fields that are written to
                        // the response's writer later in RenderPageCallback. 
                        panel.RenderControl(_updatePanelWriter);
                    }
                }
            } 

            IPage page = _owner.IPage; 
            if (page.EnableEventValidation) { 
                // If the page has event validation turned on, we need to run through
                // the render logic for the rest of the page as well. However, the 
                // rendering is essentially ignored.
                // UpdatePanels that were already rendered above do not re-render by checking
                // a flag whether they already rendered.
 
                //
 
 

 

                // DevDiv 55447: Do not use Response.Flush and a NullStream to prevent Response.Writes
                // from being written to the output stream, as calling Response.Flush causes headers to
                // be written. This prevents cookies from being issued after this, for example. 
                // Instead, use a NullWriter that ignores Writes. We can change the writer used by HttpResponse
                // using the internal SwitchWriter method. 
                // We must do this since data written via Response.Write will make the partial update 
                // response invalid.
 
                TextWriter oldWriter = null;
                bool writerSwitched = false;
                try {
                    // beginning of possible direct Response.Writes 
                    oldWriter = page.Response.SwitchWriter(TextWriter.Null);
                    // if we cant switch the writer for some reason we need to know not to switch it back again in the finally block 
                    // writerSwitched will be false 
                    writerSwitched = true;
 
                    // nullHtmlWriter captures any writes by controls to the textwriter they are passed.
                    // Note that we could possibly just let null TextWriter we switched catch this data, but this
                    // is more efficient.
                    HtmlTextWriter nullHtmlWriter = new HtmlTextWriter(TextWriter.Null); 
                    foreach (Control control in containerControl.Controls) {
                        control.RenderControl(nullHtmlWriter); 
                    } 
                }
                finally { 
                    // end of possible direct Response.Writes
                    if (writerSwitched) {
                        page.Response.SwitchWriter(oldWriter);
                    } 
                }
            } 
 
            // Re-enable parsing now that the form is done rendering its content
            parserWriter.ParseWrites = true; 
        }

        private void RenderPageCallback(HtmlTextWriter writer, Control pageControl) {
            ProcessUpdatePanels(); 

            // Although we could use the pageControl parameter it's hard to write 
            // unit tests for it. Instead we just use our own page, which is the 
            // same instance anyway (but easier to test with).
 
            HttpResponseBase response = _owner.IPage.Response;

            response.ContentType = "text/plain";
            response.Cache.SetNoServerCaching(); 

            // Render the form. It will render its tag, hidden fields, etc. 
            // and then call our render method delegate, which will in turn render 
            // all the UpdatePanels
            IHtmlForm formControl = _owner.IPage.Form; 
            formControl.SetRenderMethodDelegate(RenderFormCallback);

            // Let updatePanels write directly to Response
            _updatePanelWriter = writer; 

            // Let form header/footer write to a parser 
            ParserStringWriter parserWriter = new ParserStringWriter(); 
            ParserHtmlTextWriter formWriter = new ParserHtmlTextWriter(parserWriter);
            parserWriter.ParseWrites = true; 
            formControl.RenderControl(formWriter);
            parserWriter.ParseWrites = false;

            // Write out built-in ASP.NET hidden fields 
            // Hidden fields registered by partial-rendering compatible controls will be
            // rendered by ProcessScriptRegistration(). 
            foreach (KeyValuePair hiddenField in parserWriter.HiddenFields) { 
                if (ControlUtil.IsBuiltInHiddenField(hiddenField.Key)) {
                    EncodeString(writer, HiddenFieldToken, hiddenField.Key, hiddenField.Value); 
                }
            }

            // Write out PageRequestManager settings that can change during an async postback. 
            // This is required for dynamic UpdatePanels since the list of panels could
            // change. 
            EncodeString(writer, AsyncPostBackControlIDsToken, String.Empty, GetAsyncPostBackControlIDs(false)); 
            EncodeString(writer, PostBackControlIDsToken, String.Empty, GetPostBackControlIDs(false));
            EncodeString(writer, UpdatePanelIDsToken, String.Empty, GetAllUpdatePanelIDs()); 
            EncodeString(writer, ChildUpdatePanelIDsToken, String.Empty, GetChildUpdatePanelIDs());
            EncodeString(writer, UpdatePanelsToRefreshToken, String.Empty, GetRefreshingUpdatePanelIDs());
            EncodeString(writer, AsyncPostBackTimeoutToken, String.Empty, _owner.AsyncPostBackTimeout.ToString(CultureInfo.InvariantCulture));
            if (formWriter.FormAction != null) { 
                EncodeString(writer, FormActionToken, String.Empty, formWriter.FormAction);
            } 
            if (_owner.IPage.Header != null) { 
                string pageTitle = _owner.IPage.Title;
                if (!String.IsNullOrEmpty(pageTitle)) { 
                    EncodeString(writer, PageTitleToken, String.Empty, pageTitle);
                }
            }
            RenderDataItems(writer); 

            ProcessScriptRegistration(writer); 
 
            // We process the focus after regular script registrations to
            // make sure that if it ends up including some script that it 
            // executes last.
            ProcessFocus(writer);
        }
 
        private void RenderDataItems(HtmlTextWriter writer) {
            if (_scriptDataItems != null) { 
                foreach (ScriptDataItem dataItem in _scriptDataItems) { 
                    EncodeString(
                        writer, 
                        dataItem.IsJsonSerialized ? DataItemJsonToken : DataItemToken,
                        dataItem.Control.ClientID,
                        dataItem.DataItem);
                } 
            }
        } 
 
        internal void RenderPageRequestManagerScript(HtmlTextWriter writer) {
            // 



 

 
            // Script format: 
            // 
 
            // Writing directly to the writer is more performant than building 
            // up a big string with formatting and then writing it out later.
 
            writer.Write(@" 
");
        }

        private static void RenderUpdatePanelIDsFromList(HtmlTextWriter writer, List list) { 
            // Writing directly to the writer is more performant than building
            // up a big string with formatting and then writing it out later. 
            if (list != null && list.Count > 0) { 
                bool first = true;
                for (int i = 0; i < list.Count; i++) { 
                    if (!list[i].Visible) {
                        // If the panel isn't visible, the client doesn't need to know about it
                        continue;
                    } 
                    if (!first) {
                        writer.Write(','); 
                    } 
                    first = false;
                    writer.Write('\''); 

                    // We send down the UniqueID instead of the ClientID because
                    // we need both versions on the client. You can convert from
                    // UniqueID to ClientID, but not back. 

                    // We also send down a bool indicating whether the children of 
                    // the panel count as triggers or not. 
                    writer.Write(list[i].ChildrenAsTriggers ? 't' : 'f');
                    writer.Write(list[i].UniqueID); 

                    writer.Write('\'');
                }
            } 
        }
 
        public void SetFocus(Control control) { 
            // We always call the real Page's method at least to do parameter validation
            _owner.IPage.SetFocus(control); 

            // If it's not async, just let the page do whatever it wants. If we are
            // in an async post, we need to keep track of what to focus later on.
            if (_owner.IsInAsyncPostBack) { 
                _focusedControl = control;
                _focusedControlID = null; 
                RegisterFocusScript(); 
            }
        } 

        public void SetFocus(string clientID) {
            // We always call the real Page's method at least to do parameter validation
            _owner.IPage.SetFocus(clientID); 
            SetFocusInternal(clientID);
        } 
 
        internal void SetFocusInternal(string clientID) {
            // If it's not async, just let the page do whatever it wants. If we are 
            // in an async post, we need to keep track of what to focus later on.
            if (_owner.IsInAsyncPostBack) {
                _focusedControlID = clientID.Trim();
                _focusedControl = null; 
                RegisterFocusScript();
            } 
        } 

        internal void UnregisterUpdatePanel(UpdatePanel updatePanel) { 
            Debug.Assert(updatePanel != null);
            if ((_allUpdatePanels == null) || !_allUpdatePanels.Contains(updatePanel)) {
                throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, AtlasWeb.ScriptManager_UpdatePanelNotRegistered, updatePanel.ID), "updatePanel");
            } 
            _allUpdatePanels.Remove(updatePanel);
        } 
 
        // Specialized parser StringWriter that can detect when ASP.NET renders
        // hidden field tags. It strips them from the rendering, and 
        // they can later be retrieved via properties. It only parses while
        // ParseWrites is set to true.
        private sealed class ParserStringWriter : StringWriter {
            private enum ParserState { 
                Ready = 0,
                ReadHiddenFieldNameValue = 1, 
                ReadHiddenFieldIdAttribute = 2, 
                ReadHiddenFieldIdValue = 3,
                ReadHiddenFieldValueAttribute = 4, 
                ReadHiddenFieldValueValue = 5,
            }

            private bool _parseWrites; 

            private List _pendingWrites = new List(); 
 
            private ParserState _parserState = ParserState.Ready;
            private bool _secondTry; // Indicates that we might be accepting a 2nd write for the same parser state 
            private string _proposedHiddenFieldName = String.Empty;
            private string _matchingHiddenFieldName = String.Empty;
            private StringBuilder _proposedHiddenFieldValue = new StringBuilder();
 
            private Dictionary _hiddenFields = new Dictionary();
 
            public ParserStringWriter() 
                : base(CultureInfo.CurrentCulture) {
            } 

            // Gets the name/value pairs for hidden fields parsed from the content.
            public IDictionary HiddenFields {
                get { 
                    return _hiddenFields;
                } 
            } 

            // Indicates whether calls to Write(string) and WriteLine(string) 
            // should be parsed for specific content.
            public bool ParseWrites {
                get {
                    return _parseWrites; 
                }
                set { 
                    _parseWrites = value; 
                }
            } 

            private void FlushPendingWrites() {
                if (_pendingWrites.Count > 0) {
                    foreach (string pendingWrite in _pendingWrites) { 
                        base.Write(pendingWrite);
                    } 
                    _pendingWrites.Clear(); 
                }
            } 

            private void ParseString(string s) {
                switch (_parserState) {
                    case ParserState.Ready: 
                        if (s == "") {
                            _proposedHiddenFieldValue.Append(s); 
                        } 
                        else {
                            // If we get here that means we have a complete hidden field 
                            _pendingWrites.Clear();
                            _hiddenFields.Add(_proposedHiddenFieldName, _proposedHiddenFieldValue.ToString());
                            _proposedHiddenFieldName = String.Empty;
                            _matchingHiddenFieldName = String.Empty; 
                            _proposedHiddenFieldValue = new StringBuilder();
                            _parserState = ParserState.Ready; 
                        } 
                        break;
 
                    default:
                        _secondTry = false;
                        FlushPendingWrites();
                        base.Write(s); 
                        break;
                } 
            } 

            public override void Write(string s) { 
                if (!ParseWrites) {
                    base.Write(s);
                    return;
                } 

                ParseString(s); 
            } 

            public override void WriteLine(string value) { 
                if (!ParseWrites) {
                    base.WriteLine(value);
                    return;
                } 

                // For simplicity's sake, we turn parsed WriteLines into two 
                // calls to our parser. 
                ParseString(value);
                ParseString(NewLine); 
            }
        }

        private sealed class ParserHtmlTextWriter : HtmlTextWriter { 
            private bool _writingForm;
            private string _formAction; 
 
            public string FormAction {
                get { 
                    return _formAction;
                }
            }
 

            public ParserHtmlTextWriter(TextWriter writer) 
                : base(writer) { 
            }
 

            public override void WriteBeginTag(string tagName) {
                base.WriteBeginTag(tagName);
 
                //
                _writingForm = (tagName == "form"); 
            } 

            public override void WriteAttribute(string name, string value, bool fEncode) { 
                base.WriteAttribute(name, value, fEncode);

                //
                if (_writingForm) { 
                    if (name == "action") {
                        _formAction = value; 
                    } 
                }
            } 
        }

        private sealed class ScriptDataItem {
            private Control _control; 
            private string _dataItem;
            private bool _isJsonSerialized; 
 
            public ScriptDataItem(Control control, string dataItem, bool isJsonSerialized) {
                _control = control; 
                _dataItem = (dataItem == null) ? String.Empty : dataItem;
                _isJsonSerialized = isJsonSerialized;
            }
 
            public Control Control {
                get { 
                    return _control; 
                }
            } 

            public string DataItem {
                get {
                    return _dataItem; 
                }
            } 
 
            public bool IsJsonSerialized {
                get { 
                    return _isJsonSerialized;
                }
            }
        } 

        private sealed class ScriptDataItemCollection : List { 
            public bool ContainsControl(Control control) { 
                foreach (ScriptDataItem dataItem in this) {
                    if (dataItem.Control == control) { 
                        return true;
                    }
                }
                return false; 
            }
        } 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK