<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>NetQuarry &#187; Add new tag</title>
	<atom:link href="http://www.netquarry.com/index.php/tag/add-new-tag/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.netquarry.com</link>
	<description>The Enterprise Application Platform</description>
	<lastBuildDate>Wed, 21 Apr 2010 18:30:17 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Master Pages, AJAX, and Javascript</title>
		<link>http://www.netquarry.com/index.php/2009/03/master-pages-ajax-and-javascript-10292/</link>
		<comments>http://www.netquarry.com/index.php/2009/03/master-pages-ajax-and-javascript-10292/#comments</comments>
		<pubDate>Wed, 04 Mar 2009 00:19:48 +0000</pubDate>
		<dc:creator>Cam Woods</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Add new tag]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[Platform]]></category>

		<guid isPermaLink="false">http://www.netquarry.com/index.php/2009/03/master-pages-ajax-and-javascript-2-10292/</guid>
		<description><![CDATA[We recently decided to add support for MasterPages to the NetQuarry Enterprise Application Platform. The platform provides a set of .aspx “templates” that are used to host content in various configurations. The standard templates include Wizard, Console, and several flavors of Subform templates as well as support for custom templates. The basic idea is to [...]]]></description>
			<content:encoded><![CDATA[<p class="MsoNormal"><span class="articletitle1"><span style="font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color: #333333; font-size: 10pt; font-weight: normal; mso-bidi-font-weight: bold">We recently decided to add support for MasterPages to the NetQuarry Enterprise Application Platform.<span style="mso-spacerun: yes"> </span>The platform provides a set of .aspx “templates” that are used to host content in various configurations.<span style="mso-spacerun: yes"> </span>The standard templates include Wizard, Console, and several flavors of Subform templates as well as support for custom templates.<span style="mso-spacerun: yes"> </span>The basic idea is to support hosting templates in .master pages.<span style="mso-spacerun: yes"> </span>Note that NetQuarry is currently using .Net 2.0. </span> </span></p>
<p class="MsoNormal"><span class="articletitle1"><span style="font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color: #333333; font-size: 10pt; font-weight: normal; mso-bidi-font-weight: bold">Everything started out well enough.<span style="mso-spacerun: yes"> </span>I created a master page called minimal.master and added it to my project.<span style="mso-spacerun: yes"> </span>The .master file was very simple:</span></span><span class="articletitle1"><span style="font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color: #333333; font-size: 10pt; font-weight: normal; mso-bidi-font-weight: bold"> </span> </span></p>
<p class="Code"><span style="background: yellow; mso-highlight: yellow">&lt;%</span>@ <span style="color: #a31515">Master</span> <span style="color: red">Language</span>=&#8221;C#&#8221; <span style="color: red">AutoEventWireup</span>=&#8221;true&#8221; <span style="color: red">CodeBehind</span>=&#8221;minimal.master.cs&#8221; <span style="color: red">Inherits</span>=&#8221;NetQuarry.minimal&#8221; <span style="background: yellow; mso-highlight: yellow">%&gt; </span></p>
<p class="Code"><span style="background: yellow; mso-highlight: yellow">&lt;%</span>@ <span style="color: #a31515">Register</span> <span style="color: red">TagPrefix</span>=&#8221;eap&#8221; <span style="color: red">Namespace</span>=&#8221;NetQuarry.WebControls&#8221; <span style="color: red">Assembly</span>=&#8221;EAP.WebControls&#8221; <span style="background: yellow; mso-highlight: yellow">%&gt; </span></p>
<p class="Code">&lt;!<span style="color: #a31515">DOCTYPE</span> <span style="color: red">HTML</span> <span style="color: red">PUBLIC</span> &#8220;-//W3C//DTD HTML 4.0 Transitional//EN&#8221; &gt;</p>
<p class="Code">&lt;<span style="color: #a31515">html</span> <span style="color: red">xmlns</span>=&#8221;http://www.w3.org/1999/xhtml&#8221; &gt;<br />
&lt;<span style="color: #a31515">head</span> <span style="color: red">runat</span>=&#8221;server&#8221;&gt;<br />
<span style="mso-tab-count: 1"> </span>&lt;<span style="color: #a31515">title</span> <span style="color: red">runat</span>=&#8221;server&#8221; <span style="color: red">id</span>=&#8221;pageTitle&#8221;&gt;Untitled Page&lt;/<span style="color: #a31515">title</span>&gt;<br />
<span style="mso-spacerun: yes"> </span>&lt;<span style="color: #a31515">asp</span>:<span style="color: #a31515">ContentPlaceHolder</span> <span style="color: red">id</span>=&#8221;header&#8221; <span style="color: red">runat</span>=&#8221;server&#8221;&gt;<br />
<span style="mso-spacerun: yes"> </span>&lt;/<span style="color: #a31515">asp</span>:<span style="color: #a31515">ContentPlaceHolder</span>&gt;<br />
&lt;/<span style="color: #a31515">head</span>&gt;</p>
<p class="Code">&lt;<span style="color: #a31515">body</span> <span style="color: red">runat</span>=&#8221;server&#8221; <span style="color: red">id</span>=&#8221;body&#8221; <span style="color: red">class</span>=&#8221;background&#8221;&gt;<br />
<span style="mso-tab-count: 1"> </span>&lt;<span style="color: #a31515">esp</span>:<span style="color: #a31515">ContentPlaceHolder</span> <span style="color: red">id</span>=&#8221;content&#8221; <span style="color: red">runat</span>=&#8221;server&#8221;/&gt;<br />
&lt;/<span style="color: #a31515">body</span>&gt;<br />
&lt;/<span style="color: #a31515">html</span>&gt;</p>
<p class="MsoNormal"><span class="articletitle1"><span style="font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color: #333333; font-size: 10pt; font-weight: normal; mso-bidi-font-weight: bold">I made a few quick modifications to my templates wrapping my original header and body contents in appropriate asp:Content controls:</span></span><span class="articletitle1"><span style="font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color: #333333; font-size: 10pt; font-weight: normal; mso-bidi-font-weight: bold"> </span> </span></p>
<p class="Code">&lt;<span style="color: #a31515">asp</span>:<span style="color: #a31515">Content</span> <span style="color: red">ID</span>=&#8221;header&#8221; <span style="color: red">ContentPlaceHolderID</span>=&#8221;header&#8221; <span style="color: red">runat</span>=&#8221;Server&#8221;&gt;<br />
&lt;/<span style="color: #a31515">asp</span>:<span style="color: #a31515">Content</span>&gt;</p>
<p class="Code">&lt;<span style="color: #a31515">asp</span>:<span style="color: #a31515">Content</span> <span style="color: red">ID</span>=&#8221;content&#8221; <span style="color: red">ContentPlaceHolderID</span>=&#8221;content&#8221; <span style="color: red">runat</span>=&#8221;Server&#8221;&gt;<br />
&lt;/<span style="color: #a31515">asp</span>:<span style="color: #a31515">Content</span>&gt;</p>
<p class="MsoNormal"><span class="articletitle1"><span style="font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color: #333333; font-size: 10pt; font-weight: normal; mso-bidi-font-weight: bold">A bit more tweaking, the basics were there, but I still had problems.<span style="mso-spacerun: yes"> </span>The big problem was that the NetQuarry platform is used to create web applications, not web sites.<span style="mso-spacerun: yes"> </span>Our applications include a fair amount of javascript and  AJAX and using master pages had broken lots of script.<span style="mso-spacerun: yes"> </span>It didn’t take long for me to figure out that the main problem was that all my client-side elements now had mangled names.<span style="mso-spacerun: yes"> </span>For example, instead of a textbox being named something like “first_name”, it was being rendered into the HTML as “ctl00_content_first_name”.<span style="mso-spacerun: yes"> </span>This mangling broke our script, and badly. </span> </span></p>
<p class="MsoNormal"><span class="articletitle1"><span style="font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color: #333333; font-size: 10pt; font-weight: normal; mso-bidi-font-weight: bold">The cause of the mangling is the .Net NamingContainer idea.<span style="mso-spacerun: yes"> </span>NamingContainers allow a page to host multiple instances of an object by automatically generating unique client-side names that represent the control hierarchy on the server.<span style="mso-spacerun: yes"> </span>In this case, the MasterPage class itself was a NamingContainer as well as the ContentPlaceHolder control.<span style="mso-spacerun: yes"> </span>Since I hadn’t provided an ID for my MasterPage .Net named it ctl00.<span style="mso-spacerun: yes"> </span>I had named the ContentPlaceHolder for the main page content “content”.<span style="mso-spacerun: yes"> </span>So, since my existing page content was all contained in the “content” ContentPlaceHolder and it was in turn contained in the “ctl00” MasterPage, .Net composed a unique client-side name for the any control in the “content”<span style="mso-spacerun: yes"> </span>prefixed with “ctl00_content_” and, voila, broken script. </span> </span></p>
<p class="MsoNormal"><span class="articletitle1"><span style="font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color: #333333; font-size: 10pt; font-weight: normal; mso-bidi-font-weight: bold">Now NamingContainers are a great feature of .Net and they allow a lot of things to work seamlessly.<span style="mso-spacerun: yes"> </span>However, in this case I didn’t want any stinking NamingContainers.<span style="mso-spacerun: yes"> </span>Unfortunately, there’s no way to turn off the NamingContainer feature of any control marked as a NamingContainer (a control is marked as a NamingContainer by deriving from the INamingContainer marker interface).<span style="mso-spacerun: yes"> </span><span style="mso-spacerun: yes"> </span>Hint to Microsoft, this would be a good feature. </span> </span></p>
<p class="MsoNormal"><span class="articletitle1"><span style="font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color: #333333; font-size: 10pt; font-weight: normal; mso-bidi-font-weight: bold">I actually spent about two days fighting with this and scouring the internet to see if anyone else had come up with a solution.<span style="mso-spacerun: yes"> </span>I did find several partial solutions that helped me move in the right direction.<span style="mso-spacerun: yes"> </span>First there was a good article about MasterPages in general on <a href="http://www.odetocode.com/"><span style="mso-bidi-font-weight: normal">www.OdeToCode.com</span></a> –</span></span><span class="articletitle1"><span style="color: #333333; font-size: 13pt"> </span></span><a href="http://www.odetocode.com/articles/450.aspx">ASP.Net 2.0 &#8211; Master Pages: Tips, Tricks, and Traps</a>.<span style="mso-spacerun: yes"> </span>A bit more digging and I found a partial solution on Rick Strahl’s Web Log – <a href="http://www.west-wind.com/WebLog/posts/4605.aspx">Overriding ClientID and UniqueID on ASP.NET controls</a>.<span style="mso-spacerun: yes"> </span>I’ve found Rick’s blog to be very helpful in the past.<span style="mso-spacerun: yes"> </span>And, that article pointed me to one other helpful blog on glJakal blog – <a href="http://www.gljakal.com/blog/2007/09/12/getting-rid-of-the-naming-container-in-aspnet-20/">Getting rid of the Naming Container in asp.net 2.0</a>.</p>
<p class="MsoNormal">Together these articles showed how to defeat the NamingContainer for client-side naming.<span style="mso-spacerun: yes"> </span>The full code of the final solution is below, but defeating the NamingContainer for client-side id mangling involved overriding the ClientID, UniqueID, and ID properties on the MasterPage and ContentPlaceHolder classes to return null, and the NamingContainer property on the ContentPlaceHolder class to return null.<span style="mso-spacerun: yes"> </span>With that my pages rendered well and my javascript worked!</p>
<p class="MsoNormal">Alas, what didn’t work was any postbacks.<span style="mso-spacerun: yes"> </span>The problem was that the id’s of the client-side controls no longer matched the control hierarchy on the server!<span style="mso-spacerun: yes"> </span>It didn’t take me long to figure out that what I needed to do was figure out a way to make the server-side control hierarchy match my client-side naming.<span style="mso-spacerun: yes"> </span>Essentially this meant making the server-side hierarchy look like my pre-MasterPage hierarchy, as far as NamingContainers go that is.<span style="mso-spacerun: yes"> </span></p>
<p class="MsoNormal">After a day of failed attempts, I was able to work out how to accomplish this.<span style="mso-spacerun: yes"> </span>The secret was to rearrange the control tree during the page PreInit event.<span style="mso-spacerun: yes"> </span>The PreInit event is available only to Page objects and is the only time that you can rearrange controls in the way I needed to.<span style="mso-spacerun: yes"> </span>Eventually I figured out that two things needed to be done: 1) move the controls out of the MasterPage and ContentPlaceHolder controls so that .Net can match up the server-side controls with the unmangled client-side id’s, and 2) leave the controls in the MasterPage and ContentPlaceHolder controls for rendering purposes so that the contents are rendered correctly with respect to other elements in the MasterPage.</p>
<p class="MsoNormal"><strong>May 20, 2009 update:</strong> Thanks to Ritchie Annand for discovering a problem in the original code when run with .Net tracing enabled (via the &lt;trace&gt; tag) and pointing the way to a fix.  The code now includes a fix to ensure that all hosted controls get an ID which is required when tracing (see the call to AssignIDs() in TemplateMaster::OnPreRender()).  Note that there is still a glitch that affects our platform under certain circumstances when .Net tracing is enabled and <em>pageOutput </em>is turned on.</p>
<p class="MsoNormal">To use the code below you need to do just a few things:</p>
<ul style="margin-top: 0in" type="disc">
<li class="MsoNormal" style="mso-list: l0 level1 lfo1; tab-stops: list .5in">Include the code below in your project,</li>
<li class="MsoNormal" style="mso-list: l0 level1 lfo1; tab-stops: list .5in">Derive your master page from TemplateMaster instead of MasterPage,</li>
<li class="MsoNormal" style="mso-list: l0 level1 lfo1; tab-stops: list .5in">Use the &lt;eap:ContentPlaceHolder&gt; tag in place of &lt;asp:ContentPlaceHolder&gt;,</li>
<li class="MsoNormal" style="mso-list: l0 level1 lfo1; tab-stops: list .5in">In your master page .designer file, use the new ContentPlaceHolder instead of the .Net ContentPlaceHolder, and</li>
<li class="MsoNormal" style="mso-list: l0 level1 lfo1; tab-stops: list .5in">In your page’s PreInit event, call the TemplateMaster.Rehost() method, something like this:<span style="mso-spacerun: yes"> </span></li>
</ul>
<p><!-- code formatted by http://manoli.net/csharpformat/ --></p>
<pre class="csharpcode"><span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnPreInit(EventArgs e)
{
    <span class="rem">//--- Rehost controls from MasterPage/Content/ContentPlaceHolder hierarchy onto the </span>
    <span class="rem">//--- Page itself.  This has the effect of cancelling the NamingContainer effect of </span>
    <span class="rem">//--- these controls on the server. </span>

    <span class="kwrd">if</span> (<span class="kwrd">this</span>.Master <span class="kwrd">is</span> TemplateMaster)
    {
        (<span class="kwrd">this</span>.Master <span class="kwrd">as</span> TemplateMaster).Rehost();
    } 

    <span class="kwrd">base</span>.OnPreInit(e);
}</pre>
<p class="MsoNormal">And finally, here’s the code:</p>
<p><!-- code formatted by http://manoli.net/csharpformat/ --></p>
<pre class="csharpcode"><span class="rem">//---------------------------------------------------------------------------------------</span>
<span class="rem">// Copyright (c) 2005-2009 by NetQuarry, Inc.</span>
<span class="rem">// All rights reserved.</span>
<span class="rem">//</span>
<span class="rem">// Licensed under the Eiffel Forum License, version 2:</span>
<span class="rem">//</span>
<span class="rem">// 1. Permission is hereby granted to use, copy, modify and/or</span>
<span class="rem">// distribute this package, provided that:</span>
<span class="rem">// * copyright notices are retained unchanged,</span>
<span class="rem">// * any distribution of this package, whether modified or not,</span>
<span class="rem">// includes this license text.</span>
<span class="rem">// 2. Permission is hereby also granted to distribute binary programs</span>
<span class="rem">// which depend on this package. If the binary program depends on a</span>
<span class="rem">// modified version of this package, you are encouraged to publicly</span>
<span class="rem">// release the modified version of this package.</span>
<span class="rem">//</span>
<span class="rem">// THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT WARRANTY. ANY EXPRESS OR</span>
<span class="rem">// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED</span>
<span class="rem">// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE</span>
<span class="rem">// DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE TO ANY PARTY FOR ANY</span>
<span class="rem">// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL</span>
<span class="rem">// DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THIS PACKAGE.</span>
<span class="rem">//</span>
<span class="rem">// www.netquarry.com</span>
<span class="rem">//---------------------------------------------------------------------------------------</span>

<span class="kwrd">using</span> System;
<span class="kwrd">using</span> System.Web;
<span class="kwrd">using</span> System.Web.UI;
<span class="kwrd">using</span> System.Web.UI.WebControls;
<span class="kwrd">using</span> System.Web.UI.HtmlControls;
<span class="kwrd">using</span> System.Text;
<span class="kwrd">using</span> System.Collections.Generic;

[assembly: TagPrefix(<span class="str">"NetQuarry.WebControls"</span>, <span class="str">"eap"</span>)]

<span class="kwrd">namespace</span> NetQuarry.WebControls
{
    <span class="rem">/// &lt;summary&gt; </span>
    <span class="rem">/// Base class that must be used for any master page hosting platform templates. </span>
    <span class="rem">/// &lt;/summary&gt; </span>
    <span class="kwrd">public</span> <span class="kwrd">abstract</span> <span class="kwrd">class</span> TemplateMaster : System.Web.UI.MasterPage
    {
        <span class="kwrd">private</span> <span class="kwrd">class</span> ContentContainer : Control
        {
            <span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> Render(HtmlTextWriter writer)
            {
                <span class="rem">//base.Render(writer);  // Ignore the normal render. </span>
            }

            <span class="kwrd">public</span> <span class="kwrd">void</span> ExternalRender(HtmlTextWriter writer)
            {
                <span class="kwrd">base</span>.Render(writer);    <span class="rem">// Now render! </span>
            }

            <span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnPreRender(EventArgs e)
            {
                <span class="kwrd">base</span>.OnPreRender(e);

                <span class="kwrd">int</span> nIDIndex = 0;

                AssignIDs(<span class="kwrd">this</span>, <span class="kwrd">this</span>.ID, <span class="kwrd">ref</span> nIDIndex);
            }

            <span class="rem">/// &lt;summary&gt;</span>
            <span class="rem">/// In .Net TRACE enabled every control in the hierarchy MUST have and ID and our juggling rehosting </span>
            <span class="rem">/// controls messes up .Net's id assignment.  Here we recursively search through the specified control</span>
            <span class="rem">/// and provide unique ID's to any controls so lacking.</span>
            <span class="rem">/// &lt;/summary&gt;</span>
            <span class="rem">/// &lt;param name="ctrl"&gt;The control whose hierarchy should be scanned and assigned.&lt;/param&gt;</span>
            <span class="rem">/// &lt;param name="baseName"&gt;The base name for any subcontrols.&lt;/param&gt;</span>
            <span class="rem">/// &lt;param name="idIndex"&gt;The ID index to use when assigning a unique ID.&lt;/param&gt;</span>
            <span class="kwrd">private</span> <span class="kwrd">void</span> AssignIDs(Control ctrl, <span class="kwrd">string</span> baseName, <span class="kwrd">ref</span> <span class="kwrd">int</span> idIndex)
            {
                <span class="kwrd">if</span> (<span class="kwrd">string</span>.IsNullOrEmpty(ctrl.ID))
                {
                    ctrl.ID = baseName + idIndex.ToString().PadLeft(3, <span class="str">'0'</span>);
                    idIndex++;
                }

                <span class="kwrd">if</span> (ctrl.Controls != <span class="kwrd">null</span>)
                {
                    <span class="kwrd">foreach</span> (Control child <span class="kwrd">in</span> ctrl.Controls)
                    {
                        AssignIDs(child, baseName, <span class="kwrd">ref</span> idIndex);
                    }
                }
            }
        }

        <span class="kwrd">private</span> <span class="kwrd">class</span> ContentRenderer : Control
        {
            ContentContainer _container = <span class="kwrd">null</span>;

            <span class="kwrd">public</span> ContentRenderer(ContentContainer container)
            {
                _container = container;
            }

            <span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> Render(HtmlTextWriter writer)
            {
                <span class="kwrd">if</span> (_container != <span class="kwrd">null</span>) _container.ExternalRender(writer); <span class="rem">// Ask associated container to render. </span>
            }
        }

        <span class="rem">/// &lt;summary&gt; </span>
        <span class="rem">/// Defeat the effect of the .Net MasterPage being a NamingContainer with regard </span>
        <span class="rem">/// to client-side NAME and ID attributes rendering by always returning a null ClientID. </span>
        <span class="rem">/// &lt;/summary&gt; </span>
        <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">string</span> ClientID
        {
            get { <span class="kwrd">return</span> <span class="kwrd">null</span>; }
        }

        <span class="rem">/// &lt;summary&gt; </span>
        <span class="rem">/// Defeat the effect of the .Net MasterPage being a NamingContainer with regard </span>
        <span class="rem">/// to client-side NAME and ID attributes rendering by always returning a null UniqueID. </span>
        <span class="rem">/// &lt;/summary&gt; </span>
        <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">string</span> UniqueID
        {
            get { <span class="kwrd">return</span> <span class="kwrd">null</span>; }
        }

        <span class="rem">/// &lt;summary&gt; </span>
        <span class="rem">/// Defeat the effect of the .Net MasterPage being a NamingContainer with regard </span>
        <span class="rem">/// to client-side NAME and ID attributes rendering by always returning a null ID. </span>
        <span class="rem">/// &lt;/summary&gt; </span>
        <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">string</span> ID
        {
            get { <span class="kwrd">return</span> <span class="kwrd">null</span>; }
            set { <span class="kwrd">base</span>.ID = <span class="kwrd">value</span>; }
        }

        <span class="rem">/// &lt;summary&gt; </span>
        <span class="rem">/// Rehost controls from MasterPage/Content/ContentPlaceHolder hierarchy onto the </span>
        <span class="rem">/// Page itself.  This has the effect of cancelling the NamingContainer effect of </span>
        <span class="rem">/// these controls on the server.  </span>
        <span class="rem">/// &lt;/summary&gt; </span>
        <span class="rem">/// &lt;param name="parent"&gt;The parent control whose children should be rehosted.&lt;/param&gt;</span>
        <span class="rem">/// &lt;param name="idIndex"&gt;The ID index to use when providing ID's to controls so lacking.&lt;/param&gt;</span>
        <span class="kwrd">private</span> <span class="kwrd">void</span> MoveControlsToPage(Control parent, <span class="kwrd">ref</span> <span class="kwrd">int</span> idIndex)
        {
            <span class="kwrd">if</span> (<span class="kwrd">base</span>.Page != <span class="kwrd">null</span> &amp;&amp; <span class="kwrd">this</span>.Controls.Count &gt; 0)
            {
                List&lt;Control&gt; lst = <span class="kwrd">new</span> List&lt;Control&gt;(<span class="kwrd">this</span>.Controls.Count);
                ContentContainer container = <span class="kwrd">new</span> ContentContainer();                <span class="rem">// Container will host the controls w/out a NamingContainer. </span>
                ContentRenderer renderer = <span class="kwrd">new</span> ContentRenderer(container);        <span class="rem">// Renderer will render contents of container. </span>

                <span class="rem">//--- In .Net TRACE enabled every control in the hierarchy MUST have</span>
                <span class="rem">//--- and ID and our juggling rehosting controls messes up .Net's id assignment.</span>

                container.ID = <span class="str">"ctlcont"</span> + idIndex.ToString().PadLeft(3, <span class="str">'0'</span>);
                renderer.ID = <span class="str">"ctlrend"</span> + idIndex.ToString().PadLeft(3, <span class="str">'0'</span>);
                idIndex++;

                <span class="rem">//--— Create collection of all controls to move.</span>

                <span class="kwrd">for</span> (<span class="kwrd">int</span> ii = 0; ii &lt; parent.Controls.Count; ii++)
                {
                    lst.Add(parent.Controls[ii]);
                }

                <span class="rem">//--— Determine index of this container. </span>

                Control root = parent;

                <span class="kwrd">while</span> (root != <span class="kwrd">null</span> &amp;&amp; root.Parent != <span class="kwrd">null</span> &amp;&amp; !(root.Parent <span class="kwrd">is</span> Page))
                {
                    root = root.Parent;
                }

                <span class="kwrd">int</span> nIndex = (root == <span class="kwrd">null</span>) ? -1 : root.Parent.Controls.IndexOf(root);

                <span class="rem">//--— Remove controls from original parent and add them to new container. </span>

                <span class="kwrd">for</span> (<span class="kwrd">int</span> ii = 0; ii &lt; lst.Count; ii++)
                {
                    Control ctrl = lst[ii];

                    parent.Controls.Remove(ctrl);
                    container.Controls.AddAt(ii, ctrl);
                }

                <span class="rem">//--— Add new renderer to replace original controls and new container to the page itself. </span>
                <span class="rem">//—-- The container is used to extablish the control hierarchy and in this way collapsing  </span>
                <span class="rem">//—-- the MasterPage so that it doesn’t act as a NamingContainer for the purposes of the </span>
                <span class="rem">//—-- control hierarchy.  The container will ignore the control’s normal Render() method. </span>
                <span class="rem">//--— The renderer has no controls, just a reference to the container.  When the renderer’s </span>
                <span class="rem">//--— Render() method is called it will have the container render in its place.</span>

                parent.Controls.Add(renderer);                    <span class="rem">// Render controls as if contained in master. </span>
                Page.Controls.AddAt(nIndex + 1, container);        <span class="rem">// But host them flat on the page instead of nested in NamingContainers. </span>
            }
        }

        <span class="rem">/// &lt;summary&gt; </span>
        <span class="rem">/// Rehost controls from MasterPage/Content/ContentPlaceHolder hierarchy onto the </span>
        <span class="rem">/// Page itself.  This has the effect of cancelling the NamingContainer effect of </span>
        <span class="rem">/// these controls on the server.  </span>
        <span class="rem">/// &lt;/summary&gt; </span>
        <span class="rem">/// &lt;param name="parent"&gt;The tree of controls from which to rehost.&lt;/param&gt;</span>
        <span class="rem">/// &lt;param name="idIndex"&gt;The ID index to use when providing ID's to controls so lacking.&lt;/param&gt;</span>
        <span class="kwrd">private</span> <span class="kwrd">void</span> RehostMasterControls(Control parent, <span class="kwrd">ref</span> <span class="kwrd">int</span> idIndex)
        {
            <span class="rem">//--— Find all ContentPlaceHolder controls and rehost the children to the page itself. </span>

            <span class="kwrd">foreach</span> (Control ctrl <span class="kwrd">in</span> parent.Controls)
            {
                <span class="kwrd">if</span> (ctrl <span class="kwrd">is</span> NetQuarry.WebControls.ContentPlaceHolder)
                {
                    MoveControlsToPage(ctrl, <span class="kwrd">ref</span> idIndex);        <span class="rem">// Rehost children to page. </span>
                }
                <span class="kwrd">else</span>
                {
                    RehostMasterControls(ctrl, <span class="kwrd">ref</span> idIndex);    <span class="rem">// Recurse. </span>
                }
            }
        }

        <span class="rem">/// &lt;summary&gt;</span>
        <span class="rem">/// Rehost controls from MasterPage/Content/ContentPlaceHolder hierarchy onto the</span>
        <span class="rem">/// Page itself.  This has the effect of cancelling the NamingContainer effect of</span>
        <span class="rem">/// these controls on the server. </span>
        <span class="rem">/// &lt;/summary&gt;</span>
        <span class="kwrd">public</span> <span class="kwrd">void</span> Rehost()
        {
            <span class="kwrd">int</span> nIDIndex = 0;        <span class="rem">// Need to provide unique ID's for controls so lacking.</span>

            RehostMasterControls(<span class="kwrd">this</span>.Page.Master, <span class="kwrd">ref</span> nIDIndex);
        }
    }

    <span class="rem">/// &lt;summary&gt; </span>
    <span class="rem">/// Replacement control for System.Web.UI.WebControls.ContentPlaceHolder for use when it is desired </span>
    <span class="rem">/// to NOT have the MasterPage, Content, and ContentPlaceHolder controls behave as naming </span>
    <span class="rem">/// containers.  There are two aspects to this: 1) the effect a NamingContainer has on the  </span>
    <span class="rem">/// client-side control NAME and ID mangling, and 2) the control hierarchy on the server. </span>
    <span class="rem">/// &lt;/summary&gt; </span>
    <span class="kwrd">public</span> <span class="kwrd">class</span> ContentPlaceHolder : System.Web.UI.WebControls.ContentPlaceHolder
    {
        <span class="rem">/// &lt;summary&gt; </span>
        <span class="rem">/// Defeat the effect of the .Net ContentPlaceHolder being a NamingContainer with regard </span>
        <span class="rem">/// to client-side NAME and ID attributes rendering by always returning a null NamingContainer. </span>
        <span class="rem">/// &lt;/summary&gt; </span>
        <span class="kwrd">public</span> <span class="kwrd">override</span> Control NamingContainer
        {
            get { <span class="kwrd">return</span> <span class="kwrd">null</span>; }
        }

        <span class="rem">/// &lt;summary&gt; </span>
        <span class="rem">/// Defeat the effect of the .Net ContentPlaceHolder being a NamingContainer with regard </span>
        <span class="rem">/// to client-side NAME and ID attributes rendering by always returning a null ClientID. </span>
        <span class="rem">/// &lt;/summary&gt; </span>
        <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">string</span> ClientID
        {
            get { <span class="kwrd">return</span> <span class="kwrd">null</span>; }
        }

        <span class="rem">/// &lt;summary&gt; </span>
        <span class="rem">/// Defeat the effect of the .Net ContentPlaceHolder being a NamingContainer with regard </span>
        <span class="rem">/// to client-side NAME and ID attributes rendering by always returning a null UniqueID. </span>
        <span class="rem">/// &lt;/summary&gt; </span>
        <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">string</span> UniqueID
        {
            get { <span class="kwrd">return</span> <span class="kwrd">null</span>; }
        }

        <span class="rem">/// &lt;summary&gt; </span>
        <span class="rem">/// Defeat the effect of the .Net ContentPlaceHolder being a NamingContainer with regard </span>
        <span class="rem">/// to client-side NAME and ID attributes rendering by always returning a null ID. </span>
        <span class="rem">/// &lt;/summary&gt; </span>
        <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">string</span> ID
        {
            get { <span class="kwrd">return</span> <span class="kwrd">null</span>; }
            set { <span class="kwrd">base</span>.ID = <span class="kwrd">value</span>; }
        }
    }
}</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.netquarry.com/index.php/2009/03/master-pages-ajax-and-javascript-10292/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
	</channel>
</rss>
