<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
  <channel>
    <title>Notes on Code</title>
    <link>http://www.notesoncode.com/articles/</link>
    <description>Technical weblog of Keith Rimington.</description>
    <language>en-us</language>
    <copyright>Keith Rimington</copyright>
    <lastBuildDate>Sat, 02 Aug 2008 00:30:11 GMT</lastBuildDate>
    <generator>newtelligence dasBlog 2.1.8102.813</generator>
    <managingEditor>Keith.Rimington@aggiemail.usu.edu</managingEditor>
    <webMaster>Keith.Rimington@aggiemail.usu.edu</webMaster>
    <item>
      <trackback:ping>http://www.notesoncode.com/articles/Trackback.aspx?guid=fdb07dde-b422-4cbd-8145-df685c38397c</trackback:ping>
      <pingback:server>http://www.notesoncode.com/articles/pingback.aspx</pingback:server>
      <pingback:target>http://www.notesoncode.com/articles/PermaLink,guid,fdb07dde-b422-4cbd-8145-df685c38397c.aspx</pingback:target>
      <dc:creator>Administrator</dc:creator>
      <wfw:comment>http://www.notesoncode.com/articles/CommentView,guid,fdb07dde-b422-4cbd-8145-df685c38397c.aspx</wfw:comment>
      <wfw:commentRss>http://www.notesoncode.com/articles/SyndicationService.asmx/GetEntryCommentsRss?guid=fdb07dde-b422-4cbd-8145-df685c38397c</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
It happens so gradually that it is possible not to even notice your computer's performance
go down the drain. That's how it happened with me. My hard drive was so filthily fragmented
that it could barely limp along.
</p>
        <p>
So a friend of mine suggested I set up a scheduled task to run the defragmenter nightly.
I did this, and my the performance smoothed out nicely. I thought I'd pass it along.
</p>
        <p>
Before doing so:
</p>
        <p style="float:left; margin: 0px 10px 10px 40px">
          <img src="content/attachments/warning.png" border="0" alt="" />
        </p>
        <p style="font-size: 14pt; color: #de5d20;">
Use at your own risk. I take zero responsibility for consequences good or bad for
using this script. It worked fine for me. I run Windows XP.
</p>
        <p style="clear:both">
That said, here's the script, implemented as a command (batch) file. You can copy
it from the page, but you'll have to massage the line breaks; or you can download
the command file: <a href="content/attachments/defrag_setup.cmd">defrag_setup.cmd
(.47 KB)</a>. The original script was targeted for a computer with a C:\ and D:\ hard
drives. I stripped the scheduled task for the second drive -- I don't have two --
but I left the bit where it computes offsets so that you don't try to defrag every
drive at once. If you can get your drive in good condition, it should always defrag
in only a few minutes; especially for a home PC that is defragmenting every single
night.
</p>
        <pre class="code">@echo off
echo <span class="hl str">""</span><span class="hl sym">-------------------------------------------------------</span> echo <span class="hl str">""</span> Script
for defraging hard drives echo <span class="hl str">""</span> Use at your own risk <span class="hl sym">:)</span> echo <span class="hl str">""</span><span class="hl sym">-------------------------------------------------------</span><span class="hl kwb">SET</span> Start_Time<span class="hl sym">=</span><span class="hl num">1</span><span class="hl kwb">SET</span> Offset_Time<span class="hl sym">=</span><span class="hl num">1</span><span class="hl kwb">SET</span> Start_Time_C<span class="hl sym">=%</span>Start_Time<span class="hl sym">%</span><span class="hl kwb">SET</span><span class="hl sym">/</span>a
Start_Time_D<span class="hl sym">=</span>Start_Time<span class="hl sym">+</span>Offset_Time
@echo on schtasks <span class="hl sym">/</span>Create <span class="hl sym">/</span>tn <span class="hl str">"Defrag
Drive C"</span><span class="hl sym">/</span>tr <span class="hl str">"C:\windows\system32\defrag.exe
C: -f -v"</span><span class="hl sym">/</span>sc daily <span class="hl sym">/</span>st <span class="hl str">"0%Start_Time_C%:00:00"</span><span class="hl sym">/</span>ru <span class="hl str">"System"</span></pre>
        <img width="0" height="0" src="http://www.notesoncode.com/articles/aggbug.ashx?id=fdb07dde-b422-4cbd-8145-df685c38397c" />
      </body>
      <title>Automate your Defrag in Windows XP</title>
      <guid isPermaLink="false">http://www.notesoncode.com/articles/PermaLink,guid,fdb07dde-b422-4cbd-8145-df685c38397c.aspx</guid>
      <link>http://www.notesoncode.com/articles/2008/08/02/AutomateYourDefragInWindowsXP.aspx</link>
      <pubDate>Sat, 02 Aug 2008 00:30:11 GMT</pubDate>
      <description>&lt;p&gt;
It happens so gradually that it is possible not to even notice your computer's performance
go down the drain. That's how it happened with me. My hard drive was so filthily fragmented
that it could barely limp along.
&lt;/p&gt;
&lt;p&gt;
So a friend of mine suggested I set up a scheduled task to run the defragmenter nightly.
I did this, and my the performance smoothed out nicely. I thought I'd pass it along.
&lt;/p&gt;
&lt;p&gt;
Before doing so:
&lt;/p&gt;
&lt;p style="float:left; margin: 0px 10px 10px 40px"&gt;
&lt;img src="content/attachments/warning.png" border="0" alt="" /&gt;
&lt;/p&gt;
&lt;p style="font-size: 14pt; color: #de5d20;"&gt;
Use at your own risk. I take zero responsibility for consequences good or bad for
using this script. It worked fine for me. I run Windows XP.
&lt;/p&gt;
&lt;p style="clear:both"&gt;
That said, here's the script, implemented as a command (batch) file. You can copy
it from the page, but you'll have to massage the line breaks; or you can download
the command file: &lt;a href="content/attachments/defrag_setup.cmd"&gt;defrag_setup.cmd
(.47 KB)&lt;/a&gt;. The original script was targeted for a computer with a C:\ and D:\ hard
drives. I stripped the scheduled task for the second drive -- I don't have two --
but I left the bit where it computes offsets so that you don't try to defrag every
drive at once. If you can get your drive in good condition, it should always defrag
in only a few minutes; especially for a home PC that is defragmenting every single
night.
&lt;/p&gt;
&lt;pre class="code"&gt;@echo off
echo &lt;span class="hl str"&gt;""&lt;/span&gt; &lt;span class="hl sym"&gt;-------------------------------------------------------&lt;/span&gt; echo &lt;span class="hl str"&gt;""&lt;/span&gt; Script
for defraging hard drives echo &lt;span class="hl str"&gt;""&lt;/span&gt; Use at your own risk &lt;span class="hl sym"&gt;:)&lt;/span&gt; echo &lt;span class="hl str"&gt;""&lt;/span&gt; &lt;span class="hl sym"&gt;-------------------------------------------------------&lt;/span&gt; &lt;span class="hl kwb"&gt;SET&lt;/span&gt; Start_Time&lt;span class="hl sym"&gt;=&lt;/span&gt;&lt;span class="hl num"&gt;1&lt;/span&gt; &lt;span class="hl kwb"&gt;SET&lt;/span&gt; Offset_Time&lt;span class="hl sym"&gt;=&lt;/span&gt;&lt;span class="hl num"&gt;1&lt;/span&gt; &lt;span class="hl kwb"&gt;SET&lt;/span&gt; Start_Time_C&lt;span class="hl sym"&gt;=%&lt;/span&gt;Start_Time&lt;span class="hl sym"&gt;%&lt;/span&gt; &lt;span class="hl kwb"&gt;SET&lt;/span&gt; &lt;span class="hl sym"&gt;/&lt;/span&gt;a
Start_Time_D&lt;span class="hl sym"&gt;=&lt;/span&gt;Start_Time&lt;span class="hl sym"&gt;+&lt;/span&gt;Offset_Time
@echo on schtasks &lt;span class="hl sym"&gt;/&lt;/span&gt;Create &lt;span class="hl sym"&gt;/&lt;/span&gt;tn &lt;span class="hl str"&gt;"Defrag
Drive C"&lt;/span&gt; &lt;span class="hl sym"&gt;/&lt;/span&gt;tr &lt;span class="hl str"&gt;"C:\windows\system32\defrag.exe
C: -f -v"&lt;/span&gt; &lt;span class="hl sym"&gt;/&lt;/span&gt;sc daily &lt;span class="hl sym"&gt;/&lt;/span&gt;st &lt;span class="hl str"&gt;"0%Start_Time_C%:00:00"&lt;/span&gt; &lt;span class="hl sym"&gt;/&lt;/span&gt;ru &lt;span class="hl str"&gt;"System"&lt;/span&gt; &lt;/pre&gt;&lt;img width="0" height="0" src="http://www.notesoncode.com/articles/aggbug.ashx?id=fdb07dde-b422-4cbd-8145-df685c38397c" /&gt;</description>
      <comments>http://www.notesoncode.com/articles/CommentView,guid,fdb07dde-b422-4cbd-8145-df685c38397c.aspx</comments>
    </item>
    <item>
      <trackback:ping>http://www.notesoncode.com/articles/Trackback.aspx?guid=35099b90-0bbe-4598-8554-07a8ce56bdf3</trackback:ping>
      <pingback:server>http://www.notesoncode.com/articles/pingback.aspx</pingback:server>
      <pingback:target>http://www.notesoncode.com/articles/PermaLink,guid,35099b90-0bbe-4598-8554-07a8ce56bdf3.aspx</pingback:target>
      <dc:creator>Administrator</dc:creator>
      <wfw:comment>http://www.notesoncode.com/articles/CommentView,guid,35099b90-0bbe-4598-8554-07a8ce56bdf3.aspx</wfw:comment>
      <wfw:commentRss>http://www.notesoncode.com/articles/SyndicationService.asmx/GetEntryCommentsRss?guid=35099b90-0bbe-4598-8554-07a8ce56bdf3</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
ASP.NET control collections are finicky. They are the most difficult to handle when
trying to modify a control collection from a scope outside of that control. The mischievous
error sneaked up on me <a href="2007/07/07/ModifyingControlCollections.aspx">some
time ago</a>. It manifests itself with the following error:
</p>
        <blockquote>"The control collection cannot be modified during DataBind, Init, Load,
PreRender or Unload phases."</blockquote>
        <p>
While fiddling around for a friend I came across some interesting behavior. Perhaps
it is best to just show the code and disclaim my ignorance.
</p>
        <p>
Suppose I have an ASP.NET 2.0 application containing two user controls implementing
an interface <code>IReadyable</code>.
</p>
        <pre class="code">
          <span class="hl kwa">public interface</span> IReadyable <span class="hl sym">{</span><span class="hl kwa">event</span> EventHandler
Ready<span class="hl sym">;</span><span class="hl sym">}</span></pre>
        <p>
Each user control contains handling code to satisfy the interface, like so:
</p>
        <pre class="code">
          <span class="hl kwa">public event</span> EventHandler Ready<span class="hl sym">;</span><span class="hl kwa">protected
override</span><span class="hl kwb">void</span><span class="hl kwd">OnLoad</span><span class="hl sym">(</span>EventArgs
e<span class="hl sym">)</span><span class="hl sym">{</span><span class="hl kwa">this</span><span class="hl sym">.</span><span class="hl kwd">OnReady</span><span class="hl sym">(</span>EventArgs<span class="hl sym">.</span>Empty<span class="hl sym">);</span><span class="hl sym">}</span><span class="hl kwa">private</span><span class="hl kwb">void</span><span class="hl kwd">OnReady</span><span class="hl sym">(</span>EventArgs
e<span class="hl sym">)</span><span class="hl sym">{</span><span class="hl kwa">if</span><span class="hl sym">(</span>Ready <span class="hl sym">!=</span><span class="hl kwa">null</span><span class="hl sym">)</span><span class="hl sym">{</span><span class="hl kwa">this</span><span class="hl sym">.</span><span class="hl kwd">Ready</span><span class="hl sym">(</span><span class="hl kwa">this</span><span class="hl sym">,</span> e<span class="hl sym">);</span><span class="hl sym">}</span><span class="hl sym">}</span></pre>
        <p>
The idea is that we can use the <code>Ready</code> event to signal a time to swap
user controls in and out of our page. Allright, now to set up the <a href="http://en.wikipedia.org/wiki/Straw_man" target="_blank">straw
man</a>. We have a page that contains a placeholder. At some point, one of our user
controls is added to the control collection of the placeholder. When the <code>OnLoad</code> event
of the control fires, the handler activates the <code>Ready</code> event as well.
</p>
        <p>
Our application code responds to the ready event by swapping the user control for
another. This causes the peculiar exception.
</p>
        <pre class="code">
          <span class="hl slc">/// &lt;summary&gt;</span>
          <span class="hl slc">///
This method wires up the event handlers early in the page lifecycle,</span>
          <span class="hl slc">///
but not early enough to allow us to modify some control collections.</span>
          <span class="hl slc">///
&lt;/summary&gt;</span>
          <span class="hl kwa">protected</span>
          <span class="hl kwb">void</span>
          <span class="hl kwd">Page_Load</span>
          <span class="hl sym">(</span>
          <span class="hl kwb">object</span> sender<span class="hl sym">,</span> EventArgs
e<span class="hl sym">)</span><span class="hl sym">{</span><span class="hl kwa"> base</span><span class="hl sym">.</span><span class="hl kwd">OnInit</span><span class="hl sym">(</span>e<span class="hl sym">);</span> IReadyable
readyable <span class="hl sym">= (</span>IReadyable<span class="hl sym">)</span><span class="hl kwa">this</span><span class="hl sym">.</span><span class="hl kwd">LoadControl</span><span class="hl sym">(</span><span class="hl str">"~/MailControl01.ascx"</span><span class="hl sym">);</span> readyable<span class="hl sym">.</span>Ready <span class="hl sym">+=</span><span class="hl kwa">new</span><span class="hl kwd">EventHandler</span><span class="hl sym">(</span>readyable_Ready<span class="hl sym">);</span><span class="hl kwa">this</span><span class="hl sym">.</span>placeHolder<span class="hl sym">.</span>Controls<span class="hl sym">.</span><span class="hl kwd">Add</span><span class="hl sym">((</span>Control<span class="hl sym">)</span>readyable<span class="hl sym">);</span><span class="hl sym">}</span><span class="hl slc">///
&lt;summary&gt;</span><span class="hl slc">/// This method does not work because
it is invoked too late in the page lifecycle.</span><span class="hl slc">/// &lt;/summary&gt;</span><span class="hl kwb">void</span><span class="hl kwd">readyable_Ready</span><span class="hl sym">(</span><span class="hl kwb">object</span> sender<span class="hl sym">,</span> EventArgs
e<span class="hl sym">)</span><span class="hl sym">{</span><span class="hl kwa">this</span><span class="hl sym">.</span>placeHolder<span class="hl sym">.</span>Controls<span class="hl sym">.</span><span class="hl kwd">Clear</span><span class="hl sym">();</span><span class="hl slc">//
&lt;-- An exception is thrown here.</span> IReadyable readyable <span class="hl sym">=
(</span>IReadyable<span class="hl sym">)</span><span class="hl kwa">this</span><span class="hl sym">.</span><span class="hl kwd">LoadControl</span><span class="hl sym">(</span><span class="hl str">"~/MailControl02.ascx"</span><span class="hl sym">);</span> readyable<span class="hl sym">.</span>Ready <span class="hl sym">+=</span><span class="hl kwa">new</span><span class="hl kwd">EventHandler</span><span class="hl sym">(</span>again_Ready<span class="hl sym">);</span><span class="hl kwa">this</span><span class="hl sym">.</span>placeHolder<span class="hl sym">.</span>Controls<span class="hl sym">.</span><span class="hl kwd">Add</span><span class="hl sym">((</span>Control<span class="hl sym">)</span>readyable<span class="hl sym">);</span><span class="hl sym">}</span><span class="hl slc">///
&lt;summary&gt;</span><span class="hl slc">/// Stub for an event handler.</span><span class="hl slc">///
&lt;/summary&gt;</span><span class="hl kwb">void</span><span class="hl kwd">again_Ready</span><span class="hl sym">(</span><span class="hl kwb">object</span> sender<span class="hl sym">,</span> EventArgs
e<span class="hl sym">)</span><span class="hl sym">{</span><span class="hl sym">}</span></pre>
        <p>
Notice the first line in the <code>readyable_Ready</code> method?
</p>
        <p>
Now for the interesting behavior. I say interesting because the error states that
control collections are unmodifyable during the Init and Load phase; however, if you
swap <code>Page_Load</code> for an override on the page's <code>OnInit</code> method,
and swap the user control's <code>OnLoad</code> override for an <code>OnInit</code> override,
no exception occurs. Everything works just fine. I suppose there are some arcane rules
I am unaware of.
</p>
        <p>
Granted, in my day-to-day development, I avoid the entire issue by creating custom
server controls. I make each control responsible for its own control collection and
ignorant of anything outside. It seems a control can modify its own collection any
time it pleases, although there are some costs to doing it late in the page lifecycle.
I found this page from Microsoft helpful: <a href="http://msdn.microsoft.com/en-us/library/ms178472.aspx" target="_blank">http://msdn.microsoft.com/en-us/library/ms178472.aspx</a>.
</p>
        <p>
I hope this turns out helpful for someone. A full demo is attached here: <a href="content/attachments/ControlCollections.zip">ControlCollections.zip
(6.21 KB)</a></p>
        <p>
Happy coding.
</p>
        <img width="0" height="0" src="http://www.notesoncode.com/articles/aggbug.ashx?id=35099b90-0bbe-4598-8554-07a8ce56bdf3" />
      </body>
      <title>More on Control Collections</title>
      <guid isPermaLink="false">http://www.notesoncode.com/articles/PermaLink,guid,35099b90-0bbe-4598-8554-07a8ce56bdf3.aspx</guid>
      <link>http://www.notesoncode.com/articles/2008/07/31/MoreOnControlCollections.aspx</link>
      <pubDate>Thu, 31 Jul 2008 03:33:06 GMT</pubDate>
      <description>&lt;p&gt;
ASP.NET control collections are finicky. They are the most difficult to handle when
trying to modify a control collection from a scope outside of that control. The mischievous
error sneaked up on me &lt;a href="2007/07/07/ModifyingControlCollections.aspx"&gt;some
time ago&lt;/a&gt;. It manifests itself with the following error:
&lt;/p&gt;
&lt;blockquote&gt;"The control collection cannot be modified during DataBind, Init, Load,
PreRender or Unload phases."&lt;/blockquote&gt; 
&lt;p&gt;
While fiddling around for a friend I came across some interesting behavior. Perhaps
it is best to just show the code and disclaim my ignorance.
&lt;/p&gt;
&lt;p&gt;
Suppose I have an ASP.NET 2.0 application containing two user controls implementing
an interface &lt;code&gt;IReadyable&lt;/code&gt;.
&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span class="hl kwa"&gt;public interface&lt;/span&gt; IReadyable &lt;span class="hl sym"&gt;{&lt;/span&gt; &lt;span class="hl kwa"&gt;event&lt;/span&gt; EventHandler
Ready&lt;span class="hl sym"&gt;;&lt;/span&gt; &lt;span class="hl sym"&gt;}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
Each user control contains handling code to satisfy the interface, like so:
&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span class="hl kwa"&gt;public event&lt;/span&gt; EventHandler Ready&lt;span class="hl sym"&gt;;&lt;/span&gt; &lt;span class="hl kwa"&gt;protected
override&lt;/span&gt; &lt;span class="hl kwb"&gt;void&lt;/span&gt; &lt;span class="hl kwd"&gt;OnLoad&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;EventArgs
e&lt;span class="hl sym"&gt;)&lt;/span&gt; &lt;span class="hl sym"&gt;{&lt;/span&gt; &lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;OnReady&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;EventArgs&lt;span class="hl sym"&gt;.&lt;/span&gt;Empty&lt;span class="hl sym"&gt;);&lt;/span&gt; &lt;span class="hl sym"&gt;}&lt;/span&gt; &lt;span class="hl kwa"&gt;private&lt;/span&gt; &lt;span class="hl kwb"&gt;void&lt;/span&gt; &lt;span class="hl kwd"&gt;OnReady&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;EventArgs
e&lt;span class="hl sym"&gt;)&lt;/span&gt; &lt;span class="hl sym"&gt;{&lt;/span&gt; &lt;span class="hl kwa"&gt;if&lt;/span&gt; &lt;span class="hl sym"&gt;(&lt;/span&gt;Ready &lt;span class="hl sym"&gt;!=&lt;/span&gt; &lt;span class="hl kwa"&gt;null&lt;/span&gt;&lt;span class="hl sym"&gt;)&lt;/span&gt; &lt;span class="hl sym"&gt;{&lt;/span&gt; &lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;Ready&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;,&lt;/span&gt; e&lt;span class="hl sym"&gt;);&lt;/span&gt; &lt;span class="hl sym"&gt;}&lt;/span&gt; &lt;span class="hl sym"&gt;}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
The idea is that we can use the &lt;code&gt;Ready&lt;/code&gt; event to signal a time to swap
user controls in and out of our page. Allright, now to set up the &lt;a href="http://en.wikipedia.org/wiki/Straw_man" target="_blank"&gt;straw
man&lt;/a&gt;. We have a page that contains a placeholder. At some point, one of our user
controls is added to the control collection of the placeholder. When the &lt;code&gt;OnLoad&lt;/code&gt; event
of the control fires, the handler activates the &lt;code&gt;Ready&lt;/code&gt; event as well.
&lt;/p&gt;
&lt;p&gt;
Our application code responds to the ready event by swapping the user control for
another. This causes the peculiar exception.
&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span class="hl slc"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt; &lt;span class="hl slc"&gt;///
This method wires up the event handlers early in the page lifecycle,&lt;/span&gt; &lt;span class="hl slc"&gt;///
but not early enough to allow us to modify some control collections.&lt;/span&gt; &lt;span class="hl slc"&gt;///
&amp;lt;/summary&amp;gt;&lt;/span&gt; &lt;span class="hl kwa"&gt;protected&lt;/span&gt; &lt;span class="hl kwb"&gt;void&lt;/span&gt; &lt;span class="hl kwd"&gt;Page_Load&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl kwb"&gt;object&lt;/span&gt; sender&lt;span class="hl sym"&gt;,&lt;/span&gt; EventArgs
e&lt;span class="hl sym"&gt;)&lt;/span&gt; &lt;span class="hl sym"&gt;{&lt;/span&gt; &lt;span class="hl kwa"&gt; base&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;OnInit&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;e&lt;span class="hl sym"&gt;);&lt;/span&gt; IReadyable
readyable &lt;span class="hl sym"&gt;= (&lt;/span&gt;IReadyable&lt;span class="hl sym"&gt;)&lt;/span&gt;&lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;LoadControl&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl str"&gt;"~/MailControl01.ascx"&lt;/span&gt;&lt;span class="hl sym"&gt;);&lt;/span&gt; readyable&lt;span class="hl sym"&gt;.&lt;/span&gt;Ready &lt;span class="hl sym"&gt;+=&lt;/span&gt; &lt;span class="hl kwa"&gt;new&lt;/span&gt; &lt;span class="hl kwd"&gt;EventHandler&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;readyable_Ready&lt;span class="hl sym"&gt;);&lt;/span&gt; &lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;placeHolder&lt;span class="hl sym"&gt;.&lt;/span&gt;Controls&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;Add&lt;/span&gt;&lt;span class="hl sym"&gt;((&lt;/span&gt;Control&lt;span class="hl sym"&gt;)&lt;/span&gt;readyable&lt;span class="hl sym"&gt;);&lt;/span&gt; &lt;span class="hl sym"&gt;}&lt;/span&gt; &lt;span class="hl slc"&gt;///
&amp;lt;summary&amp;gt;&lt;/span&gt; &lt;span class="hl slc"&gt;/// This method does not work because
it is invoked too late in the page lifecycle.&lt;/span&gt; &lt;span class="hl slc"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt; &lt;span class="hl kwb"&gt;void&lt;/span&gt; &lt;span class="hl kwd"&gt;readyable_Ready&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl kwb"&gt;object&lt;/span&gt; sender&lt;span class="hl sym"&gt;,&lt;/span&gt; EventArgs
e&lt;span class="hl sym"&gt;)&lt;/span&gt; &lt;span class="hl sym"&gt;{&lt;/span&gt; &lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;placeHolder&lt;span class="hl sym"&gt;.&lt;/span&gt;Controls&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;Clear&lt;/span&gt;&lt;span class="hl sym"&gt;();&lt;/span&gt; &lt;span class="hl slc"&gt;//
&amp;lt;-- An exception is thrown here.&lt;/span&gt; IReadyable readyable &lt;span class="hl sym"&gt;=
(&lt;/span&gt;IReadyable&lt;span class="hl sym"&gt;)&lt;/span&gt;&lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;LoadControl&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl str"&gt;"~/MailControl02.ascx"&lt;/span&gt;&lt;span class="hl sym"&gt;);&lt;/span&gt; readyable&lt;span class="hl sym"&gt;.&lt;/span&gt;Ready &lt;span class="hl sym"&gt;+=&lt;/span&gt; &lt;span class="hl kwa"&gt;new&lt;/span&gt; &lt;span class="hl kwd"&gt;EventHandler&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;again_Ready&lt;span class="hl sym"&gt;);&lt;/span&gt; &lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;placeHolder&lt;span class="hl sym"&gt;.&lt;/span&gt;Controls&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;Add&lt;/span&gt;&lt;span class="hl sym"&gt;((&lt;/span&gt;Control&lt;span class="hl sym"&gt;)&lt;/span&gt;readyable&lt;span class="hl sym"&gt;);&lt;/span&gt; &lt;span class="hl sym"&gt;}&lt;/span&gt; &lt;span class="hl slc"&gt;///
&amp;lt;summary&amp;gt;&lt;/span&gt; &lt;span class="hl slc"&gt;/// Stub for an event handler.&lt;/span&gt; &lt;span class="hl slc"&gt;///
&amp;lt;/summary&amp;gt;&lt;/span&gt; &lt;span class="hl kwb"&gt;void&lt;/span&gt; &lt;span class="hl kwd"&gt;again_Ready&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl kwb"&gt;object&lt;/span&gt; sender&lt;span class="hl sym"&gt;,&lt;/span&gt; EventArgs
e&lt;span class="hl sym"&gt;)&lt;/span&gt; &lt;span class="hl sym"&gt;{&lt;/span&gt; &lt;span class="hl sym"&gt;}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
Notice the first line in the &lt;code&gt;readyable_Ready&lt;/code&gt; method?
&lt;/p&gt;
&lt;p&gt;
Now for the interesting behavior. I say interesting because the error states that
control collections are unmodifyable during the Init and Load phase; however, if you
swap &lt;code&gt;Page_Load&lt;/code&gt; for an override on the page's &lt;code&gt;OnInit&lt;/code&gt; method,
and swap the user control's &lt;code&gt;OnLoad&lt;/code&gt; override for an &lt;code&gt;OnInit&lt;/code&gt; override,
no exception occurs. Everything works just fine. I suppose there are some arcane rules
I am unaware of.
&lt;/p&gt;
&lt;p&gt;
Granted, in my day-to-day development, I avoid the entire issue by creating custom
server controls. I make each control responsible for its own control collection and
ignorant of anything outside. It seems a control can modify its own collection any
time it pleases, although there are some costs to doing it late in the page lifecycle.
I found this page from Microsoft helpful: &lt;a href="http://msdn.microsoft.com/en-us/library/ms178472.aspx" target="_blank"&gt;http://msdn.microsoft.com/en-us/library/ms178472.aspx&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
I hope this turns out helpful for someone. A full demo is attached here: &lt;a href="content/attachments/ControlCollections.zip"&gt;ControlCollections.zip
(6.21 KB)&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
Happy coding.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.notesoncode.com/articles/aggbug.ashx?id=35099b90-0bbe-4598-8554-07a8ce56bdf3" /&gt;</description>
      <comments>http://www.notesoncode.com/articles/CommentView,guid,35099b90-0bbe-4598-8554-07a8ce56bdf3.aspx</comments>
      <category>ASP.NET</category>
      <category>C#</category>
    </item>
    <item>
      <trackback:ping>http://www.notesoncode.com/articles/Trackback.aspx?guid=e261c383-dfec-4e5b-8c55-7cb34503948b</trackback:ping>
      <pingback:server>http://www.notesoncode.com/articles/pingback.aspx</pingback:server>
      <pingback:target>http://www.notesoncode.com/articles/PermaLink,guid,e261c383-dfec-4e5b-8c55-7cb34503948b.aspx</pingback:target>
      <dc:creator>Administrator</dc:creator>
      <wfw:comment>http://www.notesoncode.com/articles/CommentView,guid,e261c383-dfec-4e5b-8c55-7cb34503948b.aspx</wfw:comment>
      <wfw:commentRss>http://www.notesoncode.com/articles/SyndicationService.asmx/GetEntryCommentsRss?guid=e261c383-dfec-4e5b-8c55-7cb34503948b</wfw:commentRss>
      <slash:comments>2</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Well, I took the plunge. The truth is, that my home-brewed blog engine was too buggy
to be practical. I found myself spending a few hours massaging code, and then left
with no time to write. Certainly, I want nothing to do with "More Code than Content"
syndrome.
</p>
        <p>
My only regret is that permalinks are fatally broken. I suppose a tool such as <a href="http://www.isapirewrite.com/" target="_blank">ISAPI
Rewrite</a> could bail me out here; but given time constraints and so few blog entries,
I'm settling for burning the ship.
</p>
        <p>
So here goes. Comments are enabled for a number of days. If you see something that
peaks your interest, join in the conversation.
</p>
        <img width="0" height="0" src="http://www.notesoncode.com/articles/aggbug.ashx?id=e261c383-dfec-4e5b-8c55-7cb34503948b" />
      </body>
      <title>Migrating to dasBlog</title>
      <guid isPermaLink="false">http://www.notesoncode.com/articles/PermaLink,guid,e261c383-dfec-4e5b-8c55-7cb34503948b.aspx</guid>
      <link>http://www.notesoncode.com/articles/2008/07/26/MigratingToDasBlog.aspx</link>
      <pubDate>Sat, 26 Jul 2008 02:19:13 GMT</pubDate>
      <description>&lt;p&gt;
Well, I took the plunge. The truth is, that my home-brewed blog engine was too buggy
to be practical. I found myself spending a few hours massaging code, and then left
with no time to write. Certainly, I want nothing to do with "More Code than Content"
syndrome.
&lt;/p&gt;
&lt;p&gt;
My only regret is that permalinks are fatally broken. I suppose a tool such as &lt;a href="http://www.isapirewrite.com/" target="_blank"&gt;ISAPI
Rewrite&lt;/a&gt; could bail me out here; but given time constraints and so few blog entries,
I'm settling for burning the ship.
&lt;/p&gt;
&lt;p&gt;
So here goes. Comments are enabled for a number of days. If you see something that
peaks your interest, join in the conversation.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.notesoncode.com/articles/aggbug.ashx?id=e261c383-dfec-4e5b-8c55-7cb34503948b" /&gt;</description>
      <comments>http://www.notesoncode.com/articles/CommentView,guid,e261c383-dfec-4e5b-8c55-7cb34503948b.aspx</comments>
      <category>Misc</category>
    </item>
    <item>
      <trackback:ping>http://www.notesoncode.com/articles/Trackback.aspx?guid=79804b9d-a777-4862-aa23-7426cb320014</trackback:ping>
      <pingback:server>http://www.notesoncode.com/articles/pingback.aspx</pingback:server>
      <pingback:target>http://www.notesoncode.com/articles/PermaLink,guid,79804b9d-a777-4862-aa23-7426cb320014.aspx</pingback:target>
      <dc:creator>Administrator</dc:creator>
      <wfw:commentRss>http://www.notesoncode.com/articles/SyndicationService.asmx/GetEntryCommentsRss?guid=79804b9d-a777-4862-aa23-7426cb320014</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I encountered an interesting IE bug/feature today worth mentioning: When running a
page, I received the error message <em>"Internet Explorer cannot open the Internet
site, Operation aborted."</em> This perplexed me largely because the page seemed
to load, and behaved very kindly in Firefox.
</p>
        <p>
The problem was a single offending line of JavaScript:
</p>
        <pre class="code">document.body.appendChild(someElement);</pre>
        <p>
This line was positioned within the body tag, so it would execute before IE finished
rendering the body. Instead of saying <em>"You cannot use script to add to the
body tag until the page is fully loaded,"</em> the browser provided the cryptic <em>"Operation
aborted"</em> message.
</p>
        <p>
I hope this helps. 
</p>
        <p>
 
</p>
        <img width="0" height="0" src="http://www.notesoncode.com/articles/aggbug.ashx?id=79804b9d-a777-4862-aa23-7426cb320014" />
      </body>
      <title>Internet Explorer Cannot Open the Internet Site</title>
      <guid isPermaLink="false">http://www.notesoncode.com/articles/PermaLink,guid,79804b9d-a777-4862-aa23-7426cb320014.aspx</guid>
      <link>http://www.notesoncode.com/articles/2007/11/01/InternetExplorerCannotOpenTheInternetSite.aspx</link>
      <pubDate>Thu, 01 Nov 2007 01:44:01 GMT</pubDate>
      <description>&lt;p&gt;
I encountered an interesting IE bug/feature today worth mentioning: When running a
page, I received the error message &lt;em&gt;&amp;quot;Internet Explorer cannot open the Internet
site, Operation aborted.&amp;quot;&lt;/em&gt; This perplexed me largely because the page seemed
to load, and behaved very kindly in Firefox.
&lt;/p&gt;
&lt;p&gt;
The problem was a single offending line of JavaScript:
&lt;/p&gt;
&lt;pre class="code"&gt;document.body.appendChild(someElement);&lt;/pre&gt;
&lt;p&gt;
This line was positioned within the body tag, so it would execute before IE finished
rendering the body. Instead of saying &lt;em&gt;&amp;quot;You cannot use script to add to the
body tag until the page is fully loaded,&amp;quot;&lt;/em&gt; the browser provided the cryptic &lt;em&gt;&amp;quot;Operation
aborted&amp;quot;&lt;/em&gt; message.
&lt;/p&gt;
&lt;p&gt;
I hope this helps.&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.notesoncode.com/articles/aggbug.ashx?id=79804b9d-a777-4862-aa23-7426cb320014" /&gt;</description>
      <comments>http://www.notesoncode.com/articles/CommentView,guid,79804b9d-a777-4862-aa23-7426cb320014.aspx</comments>
      <category>Internet Explorer</category>
      <category>JavaScript</category>
    </item>
    <item>
      <trackback:ping>http://www.notesoncode.com/articles/Trackback.aspx?guid=a23faeb3-dda6-4921-983b-a952c6c525d4</trackback:ping>
      <pingback:server>http://www.notesoncode.com/articles/pingback.aspx</pingback:server>
      <pingback:target>http://www.notesoncode.com/articles/PermaLink,guid,a23faeb3-dda6-4921-983b-a952c6c525d4.aspx</pingback:target>
      <dc:creator>Administrator</dc:creator>
      <wfw:commentRss>http://www.notesoncode.com/articles/SyndicationService.asmx/GetEntryCommentsRss?guid=a23faeb3-dda6-4921-983b-a952c6c525d4</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Today, my computer got a cold. It was a brutal virus that took some doing to fix.
My gratitute to the folks who publish great tools such as <a href="http://www.spybot.info/en/">Spybot
Search &amp; Destroy</a>, <a href="http://www.lavasoftusa.com/">AdAware</a>, and <a href="http://www.trendsecure.com/portal/en-US/tools/security_tools/hijackthis">Hijack
This</a>. These tools really saved my bacon.
</p>
        <p>
Everything seems fine now, but I do think I'll reload the OS anyway. It's nice to
feel clean, and its horrid to be unsure if it is really gone. Sigh. Well, here goes...
</p>
        <img width="0" height="0" src="http://www.notesoncode.com/articles/aggbug.ashx?id=a23faeb3-dda6-4921-983b-a952c6c525d4" />
      </body>
      <title>Achoo!</title>
      <guid isPermaLink="false">http://www.notesoncode.com/articles/PermaLink,guid,a23faeb3-dda6-4921-983b-a952c6c525d4.aspx</guid>
      <link>http://www.notesoncode.com/articles/2007/10/13/Achoo.aspx</link>
      <pubDate>Sat, 13 Oct 2007 18:58:44 GMT</pubDate>
      <description>&lt;p&gt;
Today, my computer got a cold. It was a brutal virus that took some doing to fix.
My gratitute to the folks who publish great tools such as &lt;a href="http://www.spybot.info/en/"&gt;Spybot
Search &amp;amp; Destroy&lt;/a&gt;, &lt;a href="http://www.lavasoftusa.com/"&gt;AdAware&lt;/a&gt;, and &lt;a href="http://www.trendsecure.com/portal/en-US/tools/security_tools/hijackthis"&gt;Hijack
This&lt;/a&gt;. These tools really saved my bacon.
&lt;/p&gt;
&lt;p&gt;
Everything seems fine now, but I do think I'll reload the OS anyway. It's nice to
feel clean, and its horrid to be unsure if it is really gone. Sigh. Well, here goes...
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.notesoncode.com/articles/aggbug.ashx?id=a23faeb3-dda6-4921-983b-a952c6c525d4" /&gt;</description>
      <comments>http://www.notesoncode.com/articles/CommentView,guid,a23faeb3-dda6-4921-983b-a952c6c525d4.aspx</comments>
      <category>Misc</category>
    </item>
    <item>
      <trackback:ping>http://www.notesoncode.com/articles/Trackback.aspx?guid=05d26fde-402e-450c-833a-68aaaee7838a</trackback:ping>
      <pingback:server>http://www.notesoncode.com/articles/pingback.aspx</pingback:server>
      <pingback:target>http://www.notesoncode.com/articles/PermaLink,guid,05d26fde-402e-450c-833a-68aaaee7838a.aspx</pingback:target>
      <dc:creator>Administrator</dc:creator>
      <wfw:commentRss>http://www.notesoncode.com/articles/SyndicationService.asmx/GetEntryCommentsRss?guid=05d26fde-402e-450c-833a-68aaaee7838a</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I was building a new server control for <a href="http://www.atk.com/">my employer</a> when
I stumbled across this unexpected error:
</p>
        <blockquote>"The control collection cannot be modified during DataBind, Init, Load,
PreRender or Unload phases."</blockquote>
        <p>
This proved to be a misleading error. The problem occurred because I tried to modify
the <code>Control</code> collection <em>outside</em> of the new server control's own
collection. This could only be done when the <code>Parent</code> property had been
set, which is never until the <code>Init</code> cycle. Effectively, modifying a parent's
control collection is disallowed.
</p>
        <p>
The solution to my problem was ensure that all dynamically added controls were added
to the custom server control's collection only.
</p>
        <p>
Happy Coding!
</p>
        <img width="0" height="0" src="http://www.notesoncode.com/articles/aggbug.ashx?id=05d26fde-402e-450c-833a-68aaaee7838a" />
      </body>
      <title>Modifying Control Collections</title>
      <guid isPermaLink="false">http://www.notesoncode.com/articles/PermaLink,guid,05d26fde-402e-450c-833a-68aaaee7838a.aspx</guid>
      <link>http://www.notesoncode.com/articles/2007/07/07/ModifyingControlCollections.aspx</link>
      <pubDate>Sat, 07 Jul 2007 19:25:21 GMT</pubDate>
      <description>&lt;p&gt;
I was building a new server control for &lt;a href="http://www.atk.com/"&gt;my employer&lt;/a&gt; when
I stumbled across this unexpected error:
&lt;/p&gt;
&lt;blockquote&gt;"The control collection cannot be modified during DataBind, Init, Load,
PreRender or Unload phases."&lt;/blockquote&gt; 
&lt;p&gt;
This proved to be a misleading error. The problem occurred because I tried to modify
the &lt;code&gt;Control&lt;/code&gt; collection &lt;em&gt;outside&lt;/em&gt; of the new server control's own
collection. This could only be done when the &lt;code&gt;Parent&lt;/code&gt; property had been
set, which is never until the &lt;code&gt;Init&lt;/code&gt; cycle. Effectively, modifying a parent's
control collection is disallowed.
&lt;/p&gt;
&lt;p&gt;
The solution to my problem was ensure that all dynamically added controls were added
to the custom server control's collection only.
&lt;/p&gt;
&lt;p&gt;
Happy Coding!
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.notesoncode.com/articles/aggbug.ashx?id=05d26fde-402e-450c-833a-68aaaee7838a" /&gt;</description>
      <comments>http://www.notesoncode.com/articles/CommentView,guid,05d26fde-402e-450c-833a-68aaaee7838a.aspx</comments>
      <category>ASP.NET</category>
    </item>
    <item>
      <trackback:ping>http://www.notesoncode.com/articles/Trackback.aspx?guid=ad872df0-da73-44df-9c07-03b38e437995</trackback:ping>
      <pingback:server>http://www.notesoncode.com/articles/pingback.aspx</pingback:server>
      <pingback:target>http://www.notesoncode.com/articles/PermaLink,guid,ad872df0-da73-44df-9c07-03b38e437995.aspx</pingback:target>
      <dc:creator>Administrator</dc:creator>
      <wfw:commentRss>http://www.notesoncode.com/articles/SyndicationService.asmx/GetEntryCommentsRss?guid=ad872df0-da73-44df-9c07-03b38e437995</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Download the source code for this demo <a href="content/attachments/AjaxControlDemo.zip">here</a>.
</p>
        <h4>Introduction
</h4>
        <p>
The demand for high quality web interfaces is continually increasing. The movement
towards <em>Web 2.0</em> places an increasing emphasis in making a web application
look and feel like it were a home desktop application, with all the bells and whistles
attached. Users expect each page they visit to interact with them in a smooth and
natural way.
</p>
        <p>
Asynchronous JavaScript and XML, <acronym title="Asynchronous JavaScript and XML">AJAX</acronym>,
is one tool that helps to create this user experience. In a typical scenario, JavaScript
on the page sends and retrieves data from the web server asynchronously, updating
the web page without flicker and with minimal delay. <a href="http://www.google.com/" rel="nofollow">Google</a> Inc.'s <a href="http://www.gmail.com/" rel="nofollow">GMail</a> is
an example. Each GMail page retrieves content from GMail only a portion at a time,
"on demand". The entire experience is seamless.
</p>
        <p>
          <a href="http://www.microsoft.com/">Microsoft</a> recently released a framework for <a href="http://ajax.asp.net/"><acronym title="Asynchronous JavaScript and XML">AJAX</acronym></a>,
and a corresponding collection of control extenders called the <a href="http://ajax.asp.net/ajaxtoolkit">AJAX
Control Toolkit</a>. The toolkit contains several control extenders. An <acronym title="Asynchronous JavaScript and XML">AJAX</acronym> control
extender adds <acronym title="Asynchronous JavaScript and XML">AJAX</acronym> functionality
to a non-ajax web control. The extender approach can be particularly useful when there
is a requirement to add similar <acronym title="Asynchronous JavaScript and XML">AJAX</acronym> behavior
to more than one control type, such as adding behaviors to buttons, images, and panels.
</p>
        <p>
This tutorial introduces the basics of creating a custom <acronym title="Asynchronous JavaScript and XML">AJAX</acronym> control
extender. We discuss embedded resources, property decorations (attributes), and client-side
Web service calls.
</p>
        <h4>The Scenario
</h4>
        <p>
Consider a form built for a web application. The form contains several places for
input. From time to time, users flood you with questions about the meaning of each
element. You want to add some context sensitive help to the page to spare yourself
all the most frequently asked questions, saving both time and money.
</p>
        <p>
We'll create a very simple <acronym title="Asynchronous JavaScript and XML">AJAX</acronym> control
extender that wraps a server control, such as a <code>Button</code> or a <code>Label</code>,
and adds context sensitive help at the click of a mouse. Moreover, the extender will
populate the help with the results of a web service call to separate the content from
the functionality.
</p>
        <h4>Getting Started
</h4>
        <p>
Below is an example of the body of a very simple page. There are three main elements.
On each, we want to add context sensitive help. The fourth element, the <code>Panel</code> at
the bottom, is a placeholder for our help content.
</p>
        <pre class="code">
          <span class="hl kwa">&lt;form</span> id=<span class="hl str">"form1"</span> runat=<span class="hl str">"server"</span>&gt; <span class="hl kwa">&lt;asp:Button</span> ID=<span class="hl str">"Button1"</span> runat=<span class="hl str">"server"</span> Text=<span class="hl str">"Looking
for help..."</span>/&gt; <span class="hl kwa">&lt;br</span> /&gt; <span class="hl kwa">&lt;br</span> /&gt; <span class="hl kwa">&lt;asp:Image</span> ID=<span class="hl str">"Image1"</span> runat=<span class="hl str">"server"</span> ImageUrl=<span class="hl str">"~/flower.jpg"</span> /&gt; <span class="hl kwa">&lt;br</span> /&gt; <span class="hl kwa">&lt;br</span> /&gt; <span class="hl kwa">&lt;asp:Panel</span> ID=<span class="hl str">"Panel1"</span> runat=<span class="hl str">"server"</span>&gt;
This is the content of the panel.<span class="hl kwa">&lt;br</span> /&gt; If you would
like to find help, kindly click among this text.<span class="hl kwa">&lt;br</span> /&gt;
Good luck! <span class="hl kwa">&lt;/asp:Panel&gt;</span><span class="hl kwa">&lt;br</span> /&gt; <span class="hl kwa">&lt;br</span> /&gt; <span class="hl kwa">&lt;asp:Panel</span> ID=<span class="hl str">"HelpPanel"</span> runat=<span class="hl str">"server"</span> /&gt; <span class="hl kwa">&lt;br</span> /&gt; <span class="hl kwa">&lt;br</span> /&gt; <span class="hl kwa">&lt;/form&gt;</span></pre>
        <p>
To make our control extender consumable from any website, we'll compile the extender
into a separate assembly. To do this, first make sure that the extender templates
are installed. Download the <acronym title="Asynchronous JavaScript and XML">AJAX</acronym> control
toolkit from <a href="http://ajax.asp.net" rel="nofollow">http://ajax.asp.net</a>,
extract the files into the directory of choice, and execute the .vsi installers located
in the archive at <strong>AjaxControlExtender\AjaxControlExtender.vsi</strong>. Once
this is installed, add the new extender project to your Visual Studio solution by
right clicking on the solution and selecting Add -&gt; New Project, or selecting File
-&gt; Add -&gt; New Project from the menu.
</p>
        <img src="content/attachments/addnewproj.jpg" alt="" />
        <p>
Select <strong>ASP.NET AJAX Control Project</strong> from the templates.
</p>
        <img src="content/attachments/ajaxproject.gif" alt="" />
        <p>
Delete the default <code>.cs</code> and <code>.js</code> files, and create a directory, <code>Help</code> to
hold the new control. Right click on the folder, select Add -&gt; New Item, and select <strong>ASP.NET
AJAX Extender Control</strong> from the templates. Name the control "Help", since
the convention of "HelpExtender" is added by default.
</p>
        <img src="content/attachments/ajaxcontrol.jpg" alt="" />
        <p>
We now have the basic file structure for the control.
</p>
        <h4>Configuring the Namespaces
</h4>
        <p>
It is important to give some thought to the namespace conventions for your control.
There are three namespaces of immediate concern: 
</p>
        <ol>
          <li>
The namespace of your server code</li>
          <li>
The namespace of your client JavaScript</li>
          <li>
The default namespace of your assembly</li>
        </ol>
        <p>
Adjusting the namespace of server code is plain and direct. I chose <code>KbrProductions.Web.Extensions</code>,
after the pattern set by Microsoft's <code>System.Web.Extensions</code>. The client
namespace is adjusted in the <code>.js</code> file. For this project the client namespace
is <code>KbrProductions.Ajax</code>. A simple search and replace can fix the handful
of references. Finally, the default namespace of the assembly can be configured by
right clicking on the project file, selecting Properties, and editing the namespace
in the Application tab. This namespace is important because it influences embedded
resources.
</p>
        <img src="content/attachments/projproperties.jpg" alt="" />
        <p>
For the JavaScript file to be consumable by the website, we must include it as a resource
to the project assembly. Do this by selecting the file in Solution Explorer, viewing
its properties, and setting the Build Action attribute to Embedded Resource.
</p>
        <img src="content/attachments/embed.jpg" alt="" />
        <p>
Now visit the <code>HelpExtender.cs</code> file. Edit the assembly attribute to read:
</p>
        <pre class="code">
          <span class="hl sym">[</span>assembly<span class="hl sym">:</span> System<span class="hl sym">.</span>Web<span class="hl sym">.</span>UI<span class="hl sym">.</span><span class="hl kwd">WebResource</span><span class="hl sym">(</span><span class="hl str">"KbrProductions.Web.Extensions.Help.HelpBehavior.js"</span><span class="hl sym">,</span><span class="hl str">"text/javascript"</span><span class="hl sym">)]</span></pre>
        <p>
The first parameter is a resource path for the javascript file. The naming convention
for the path is: [Assembly Namespace][.directory][.FileName]. Remember, the assembly
namespace is the default namespace set in the project properties. For the directory,
use dots (.) to separate folders instead of backslashes. Misconfiguring this line
is the common cause of the following web page error:
</p>
        <blockquote>Assembly 'Extensions, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'
contains a Web resource with name 'Extensions.Help.HelpBehavior.js', but does not
contain an embedded resource with name 'Extensions.Help.HelpBehavior.js'.</blockquote>
        <p>
When in doubt, fire up <acronym title="Intermediate Language Disassembler">ILDASM</acronym> and
view the contents of the control assembly. The manifest contains the proper path for
the JavaScript file on a <code>.mresource</code> line.
</p>
        <img src="content/attachments/ildasm.jpg" alt="" />
        <p>
The extender class includes the JavaScript file by means of a <code>ClientScriptResource</code> decoration.
Modify the decoration as shown below, where the first string indicates the client
class name, and the second string specifies the resource exactly as specified in the
assembly attribute earlier in the page.
</p>
        <pre class="code">
          <span class="hl sym">[</span>
          <span class="hl kwd">ClientScriptResource</span>
          <span class="hl sym">(</span>
          <span class="hl str">"KbrProductions.Ajax.HelpBehavior"</span>
          <span class="hl sym">,</span>
          <span class="hl str">"KbrProductions.Web.Extensions.Help.HelpBehavior.js"</span>
          <span class="hl sym">)]</span>
        </pre>
        <p>
At this point, the namespaces of the control assembly should be configured.
</p>
        <h4>Server-Side Extender Properties
</h4>
        <p>
Next, we'll specify the properties that will be available as attributes to our extender
markup. Because we inherit from <code>ExtenderControlBase</code>, we already have
a <code>TargetControlID</code> property, which we can use to specify the control we
want to extend.
</p>
        <p>
We also want to specify the control that will contain the contents of our help. We
decorate the property with the <code>IDReferenceProperty</code> attribute to enable
the extender to automatically resolve the specified <code>ID</code> into a <code>ClientID</code>.
</p>
        <pre class="code">
          <span class="hl slc">/// &lt;summary&gt;</span>
          <span class="hl slc">///
ID of the control that will contain the help content.</span>
          <span class="hl slc">///
&lt;/summary&gt;</span>
          <span class="hl sym">[</span>ExtenderControlProperty<span class="hl sym">]</span><span class="hl sym">[</span><span class="hl kwd">DefaultValue</span><span class="hl sym">(</span><span class="hl str">""</span><span class="hl sym">)]</span><span class="hl sym">[</span><span class="hl kwd">IDReferenceProperty</span><span class="hl sym">(</span><span class="hl kwd">typeof</span><span class="hl sym">(</span>WebControl<span class="hl sym">))]</span><span class="hl sym">[</span><span class="hl kwd">ClientPropertyName</span><span class="hl sym">(</span><span class="hl str">"helpPanelID"</span><span class="hl sym">)]</span><span class="hl kwa">public</span><span class="hl kwb">string</span> HelpPanelID <span class="hl sym">{</span><span class="hl kwa">get</span><span class="hl sym">{</span><span class="hl kwa">return</span><span class="hl kwd">GetPropertyValue</span><span class="hl sym">(</span><span class="hl str">"HelpPanelID"</span><span class="hl sym">,</span><span class="hl str">""</span><span class="hl sym">);
}</span><span class="hl kwa">set</span><span class="hl sym">{</span><span class="hl kwd">SetPropertyValue</span><span class="hl sym">(</span><span class="hl str">"HelpPanelID"</span><span class="hl sym">,</span><span class="hl kwa">value</span><span class="hl sym">);
}</span><span class="hl sym">}</span></pre>
        <p>
Next, we'll build properties to define the location of a Web service that provides
the text for the context-sensitive help. We decorate this property as a <code>UrlProperty</code>,
which provides automatic resolving of server-relative URLs, that is, any URL starting
with "~/". We also decorate it with a <code>TypeConverter</code> to handle some Web
service specific url handling.
</p>
        <pre class="code">
          <span class="hl slc">/// &lt;summary&gt;</span>
          <span class="hl slc">///
Path to the webservice that the extender will pull the images from.</span>
          <span class="hl slc">///
&lt;/summary&gt;</span>
          <span class="hl sym">[</span>
          <span class="hl kwd">UrlProperty</span>
          <span class="hl sym">()]</span>
          <span class="hl sym">[</span>
          <span class="hl kwd">ExtenderControlProperty</span>
          <span class="hl sym">()]</span>
          <span class="hl sym">[</span>
          <span class="hl kwd">TypeConverter</span>
          <span class="hl sym">(</span>
          <span class="hl kwd">typeof</span>
          <span class="hl sym">(</span>ServicePathConverter<span class="hl sym">))]</span><span class="hl sym">[</span><span class="hl kwd">ClientPropertyName</span><span class="hl sym">(</span><span class="hl str">"servicePath"</span><span class="hl sym">)]</span><span class="hl kwa">public</span><span class="hl kwb">string</span> ServicePath <span class="hl sym">{</span><span class="hl kwa">get</span><span class="hl sym">{</span><span class="hl kwa">return</span><span class="hl kwd">GetPropertyValue</span><span class="hl sym">(</span><span class="hl str">"ServicePath"</span><span class="hl sym">,</span><span class="hl str">""</span><span class="hl sym">);
}</span><span class="hl kwa">set</span><span class="hl sym">{</span><span class="hl kwd">SetPropertyValue</span><span class="hl sym">(</span><span class="hl str">"ServicePath"</span><span class="hl sym">,</span><span class="hl kwa">value</span><span class="hl sym">);
}</span><span class="hl sym">}</span></pre>
        <p>
Next we add a required property to define which method should be called.
</p>
        <pre class="code">
          <span class="hl slc">/// &lt;summary&gt;</span>
          <span class="hl slc">///
The webservice method that will be called to supply help.</span>
          <span class="hl slc">///
&lt;/summary&gt;</span>
          <span class="hl sym">[</span>ExtenderControlProperty<span class="hl sym">]</span><span class="hl sym">[</span>RequiredProperty<span class="hl sym">]</span><span class="hl sym">[</span><span class="hl kwd">DefaultValue</span><span class="hl sym">(</span><span class="hl str">""</span><span class="hl sym">)]</span><span class="hl sym">[</span><span class="hl kwd">ClientPropertyName</span><span class="hl sym">(</span><span class="hl str">"serviceMethod"</span><span class="hl sym">)]</span><span class="hl kwa">public</span><span class="hl kwb">string</span> ServiceMethod <span class="hl sym">{</span><span class="hl kwa">get</span><span class="hl sym">{</span><span class="hl kwa">return</span><span class="hl kwd">GetPropertyValue</span><span class="hl sym">(</span><span class="hl str">"ServiceMethod"</span><span class="hl sym">,</span><span class="hl str">""</span><span class="hl sym">);
}</span><span class="hl kwa">set</span><span class="hl sym">{</span><span class="hl kwd">SetPropertyValue</span><span class="hl sym">(</span><span class="hl str">"ServiceMethod"</span><span class="hl sym">,</span><span class="hl kwa">value</span><span class="hl sym">);
}</span><span class="hl sym">}</span></pre>
        <p>
And, finally, we add a property to define a parameter for the Web service call. We
could treat this parameter as a key to determine which piece of help to return from
the service.
</p>
        <pre class="code">
          <span class="hl slc">/// &lt;summary&gt;</span>
          <span class="hl slc">///
Context key to pass to the service method to get help text.</span>
          <span class="hl slc">///
&lt;/summary&gt;</span>
          <span class="hl sym">[</span>ExtenderControlProperty<span class="hl sym">]</span><span class="hl sym">[</span><span class="hl kwd">DefaultValue</span><span class="hl sym">(</span><span class="hl str">""</span><span class="hl sym">)]</span><span class="hl sym">[</span><span class="hl kwd">ClientPropertyName</span><span class="hl sym">(</span><span class="hl str">"helpContextKey"</span><span class="hl sym">)]</span><span class="hl kwa">public</span><span class="hl kwb">string</span> HelpContextKey <span class="hl sym">{</span><span class="hl kwa">get</span><span class="hl sym">{</span><span class="hl kwa">return</span><span class="hl kwd">GetPropertyValue</span><span class="hl sym">(</span><span class="hl str">"HelpContextKey"</span><span class="hl sym">,</span><span class="hl str">""</span><span class="hl sym">);
}</span><span class="hl kwa">set</span><span class="hl sym">{</span><span class="hl kwd">SetPropertyValue</span><span class="hl sym">(</span><span class="hl str">"HelpContextKey"</span><span class="hl sym">,</span><span class="hl kwa">value</span><span class="hl sym">);
}</span><span class="hl sym">}</span></pre>
        <p>
The next step is to provide a client-side equivalent interface to these properties.
</p>
        <h4>Client-Side Extender Properties
</h4>
        <p>
Basic handling of each property from JavaScript is made extremely simple due to the
AJAX Control Toolkit. All that is required is to add variable declarations to the
constructor function, and add get/set functions to the object prototype. It is important
to note that the property names for the get and set functions are case sensitive and
should reflect the <code>ClientPropertyName</code> configured in the server-side extender
code. Additional utility variables can be added to the constructor function as well.
</p>
        <pre class="code">KbrProductions<span class="hl sym">.</span>Ajax<span class="hl sym">.</span>HelpBehavior <span class="hl sym">=</span><span class="hl kwa">function</span><span class="hl sym">(</span>element<span class="hl sym">)
{</span> KbrProductions<span class="hl sym">.</span>Ajax<span class="hl sym">.</span>HelpBehavior<span class="hl sym">.</span><span class="hl kwd">initializeBase</span><span class="hl sym">(</span><span class="hl kwa">this</span><span class="hl sym">,
[</span>element<span class="hl sym">]);</span><span class="hl kwa">this</span><span class="hl sym">.</span>_helpContextKey <span class="hl sym">=</span><span class="hl kwa">null</span><span class="hl sym">;</span><span class="hl slc">//
HelpContextKey property</span><span class="hl kwa">this</span><span class="hl sym">.</span>_serviceMethod <span class="hl sym">=</span><span class="hl kwa">null</span><span class="hl sym">;</span><span class="hl slc">//
ServiceMethod property</span><span class="hl kwa">this</span><span class="hl sym">.</span>_servicePath <span class="hl sym">=</span><span class="hl kwa">null</span><span class="hl sym">;</span><span class="hl slc">//
ServicePath property</span><span class="hl kwa">this</span><span class="hl sym">.</span>_helpPanelID <span class="hl sym">=</span><span class="hl kwa">null</span><span class="hl sym">;</span><span class="hl slc">//
HelpPanelID property</span><span class="hl kwa">this</span><span class="hl sym">.</span>_helpPanel <span class="hl sym">=</span><span class="hl kwa">null</span><span class="hl sym">;</span><span class="hl slc">//
HelpPanel element</span><span class="hl kwa">this</span><span class="hl sym">.</span>_clickHandler <span class="hl sym">=</span><span class="hl kwa">null</span><span class="hl sym">;</span><span class="hl slc">//
Click Event handler for the extended control</span><span class="hl kwa">this</span><span class="hl sym">.</span>_targetElement <span class="hl sym">=</span><span class="hl kwa">null</span><span class="hl sym">;</span><span class="hl slc">//
Element of the extended control</span><span class="hl sym">}</span> KbrProductions<span class="hl sym">.</span>Ajax<span class="hl sym">.</span>HelpBehavior<span class="hl sym">.</span><span class="hl kwa">prototype</span><span class="hl sym">=
{</span><span class="hl slc">// ...</span><span class="hl slc">// extended properties</span> get_serviceMethod <span class="hl sym">:</span><span class="hl kwa">function</span><span class="hl sym">()
{</span><span class="hl kwa">return this</span><span class="hl sym">.</span>_serviceMethod<span class="hl sym">;
},</span> set_serviceMethod <span class="hl sym">:</span><span class="hl kwa">function</span><span class="hl sym">(</span><span class="hl kwc">value</span><span class="hl sym">)
{</span><span class="hl kwa">this</span><span class="hl sym">.</span>_serviceMethod <span class="hl sym">=</span><span class="hl kwc">value</span><span class="hl sym">;
},</span> get_servicePath <span class="hl sym">:</span><span class="hl kwa">function</span><span class="hl sym">()
{</span><span class="hl kwa">return this</span><span class="hl sym">.</span>_servicePath<span class="hl sym">;
},</span> set_servicePath <span class="hl sym">:</span><span class="hl kwa">function</span><span class="hl sym">(</span><span class="hl kwc">value</span><span class="hl sym">)
{</span><span class="hl kwa">this</span><span class="hl sym">.</span>_servicePath <span class="hl sym">=</span><span class="hl kwc">value</span><span class="hl sym">;
},</span> get_helpContextKey <span class="hl sym">:</span><span class="hl kwa">function</span><span class="hl sym">()
{</span><span class="hl kwa">return this</span><span class="hl sym">.</span>_helpContextKey<span class="hl sym">;
},</span> set_helpContextKey <span class="hl sym">:</span><span class="hl kwa">function</span><span class="hl sym">(</span><span class="hl kwc">value</span><span class="hl sym">)
{</span><span class="hl kwa">this</span><span class="hl sym">.</span>_helpContextKey <span class="hl sym">=</span><span class="hl kwc">value</span><span class="hl sym">;
},</span> get_helpPanelID <span class="hl sym">:</span><span class="hl kwa">function</span><span class="hl sym">()
{</span><span class="hl kwa">return this</span><span class="hl sym">.</span>_helpPanelID<span class="hl sym">;
},</span> set_helpPanelID <span class="hl sym">:</span><span class="hl kwa">function</span><span class="hl sym">(</span><span class="hl kwc">value</span><span class="hl sym">)
{</span><span class="hl kwa">this</span><span class="hl sym">.</span>_helpPanelID <span class="hl sym">=</span><span class="hl kwc">value</span><span class="hl sym">;
}</span><span class="hl sym">}</span></pre>
        <h4>Fleshing out the Client Behavior
</h4>
        <p>
All that remains to complete our extender is to implement the client behavior. To
provide feedback to the user that a control contains help, change the mouse cursor
of the extended element. The object prototype's initialize method is a good place
to do this.
</p>
        <pre class="code">initialize <span class="hl sym">:</span><span class="hl kwa">function</span><span class="hl sym">()
{</span> KbrProductions<span class="hl sym">.</span>Ajax<span class="hl sym">.</span>HelpBehavior<span class="hl sym">.</span><span class="hl kwd">callBaseMethod</span><span class="hl sym">(</span><span class="hl kwa">this</span><span class="hl sym">,</span><span class="hl str">'initialize'</span><span class="hl sym">);</span><span class="hl slc">//
Apply the CSS cursor style, "help"</span><span class="hl kwa">this</span><span class="hl sym">.</span>_targetElement <span class="hl sym">=</span><span class="hl kwa">this</span><span class="hl sym">.</span><span class="hl kwd">get_element</span><span class="hl sym">();</span><span class="hl kwa">this</span><span class="hl sym">.</span>_targetElement<span class="hl sym">.</span>style<span class="hl sym">.</span>cursor <span class="hl sym">=</span><span class="hl str">"help"</span><span class="hl sym">;</span><span class="hl slc">//
...</span></pre>
        <p>
Next, wire up an event handler in the initialize function to handle the click event
of the target element. Use the Function.createDelegate method to create the handler.
This ensures that multiple handlers can potentially be attached to the element without
conflicting.
</p>
        <pre class="code">
          <span class="hl slc">// Attach an event handler to the click
event of the element</span>
          <span class="hl kwa">if</span>
          <span class="hl sym">(</span>
          <span class="hl kwa">this</span>
          <span class="hl sym">.</span>_targetElement<span class="hl sym">)
{</span><span class="hl kwa">this</span><span class="hl sym">.</span>_clickHandler <span class="hl sym">=</span> Function<span class="hl sym">.</span><span class="hl kwd">createDelegate</span><span class="hl sym">(</span><span class="hl kwa">this</span><span class="hl sym">,</span><span class="hl kwa">this</span><span class="hl sym">.</span>_onClick<span class="hl sym">);</span> $<span class="hl kwd">addHandler</span><span class="hl sym">(</span><span class="hl kwa">this</span><span class="hl sym">.</span>_targetElement<span class="hl sym">,</span><span class="hl str">'click'</span><span class="hl sym">,</span><span class="hl kwa">this</span><span class="hl sym">.</span>_clickHandler<span class="hl sym">);</span><span class="hl sym">}</span></pre>
        <p>
Add functionality to the dispose method to clean up the event handler. This is good
practice to keep our memory clean.
</p>
        <pre class="code">dispose <span class="hl sym">:</span><span class="hl kwa">function</span><span class="hl sym">()
{</span><span class="hl slc">// Remove the event handler from the element if attached.</span><span class="hl kwa">if</span><span class="hl sym">(</span><span class="hl kwa">this</span><span class="hl sym">.</span>_clickHandler<span class="hl sym">)
{</span> $<span class="hl kwd">removeHandler</span><span class="hl sym">(</span><span class="hl kwa">this</span><span class="hl sym">.</span>_targetElement<span class="hl sym">,</span><span class="hl str">'click'</span><span class="hl sym">,</span><span class="hl kwa">this</span><span class="hl sym">.</span>_clickHandler<span class="hl sym">);</span><span class="hl kwa">this</span><span class="hl sym">.</span>_clickHandler <span class="hl sym">=</span><span class="hl kwa">null</span><span class="hl sym">;</span><span class="hl sym">}</span> KbrProductions<span class="hl sym">.</span>Ajax<span class="hl sym">.</span>HelpBehavior<span class="hl sym">.</span><span class="hl kwd">callBaseMethod</span><span class="hl sym">(</span><span class="hl kwa">this</span><span class="hl sym">,</span><span class="hl str">'dispose'</span><span class="hl sym">);</span><span class="hl sym">},</span></pre>
        <p>
We now create the <code>this._onClick</code> function to handle the mouse click. We
first implement a few lines to prevent any full-page postback that might occur. Parameters
to the service method should be prepared as a dictionary key-value pair. We then can
invoke the method using the ASP.NET AJAX <code>Sys.Net.WebServiceProxy.invoke</code> method.
The method has seven parameters: 
</p>
        <ol>
          <li>
The path to the Web service.</li>
          <li>
The method to invoke.</li>
          <li>
A parameter to indicate whether the call should use HTTP POST. For security reasons,
this defaults to <code>false</code>.</li>
          <li>
The parameters for the method.</li>
          <li>
An event handler to be called when the service call returns successfully.</li>
          <li>
An event handler to be called if the service call fails.</li>
          <li>
Any JavaScript structure to pass to the event handler. This is a place holder if you
want to send more than the defaults.</li>
        </ol>
        <pre class="code">
          <span class="hl slc">// click event for the extended element</span> _onClick <span class="hl sym">:</span><span class="hl kwa">function</span><span class="hl sym">(</span>e<span class="hl sym">)
{</span><span class="hl slc">// prevent post back.</span> e<span class="hl sym">.</span><span class="hl kwd">preventDefault</span><span class="hl sym">();</span> e<span class="hl sym">.</span><span class="hl kwd">stopPropagation</span><span class="hl sym">();</span><span class="hl slc">//
prepare parameters, if necessary</span><span class="hl kwa">var</span> params <span class="hl sym">=</span><span class="hl kwa">null</span><span class="hl sym">;</span><span class="hl kwa">if</span><span class="hl sym">(</span><span class="hl kwa">this</span><span class="hl sym">.</span>_helpContextKey<span class="hl sym">)
{</span> params <span class="hl sym">= {</span><span class="hl str">'helpContextKey'</span><span class="hl sym">:</span><span class="hl kwa">this</span><span class="hl sym">.</span>_helpContextKey <span class="hl sym">};</span><span class="hl sym">}</span><span class="hl slc">//
Invoke the web service</span> Sys<span class="hl sym">.</span>Net<span class="hl sym">.</span>WebServiceProxy<span class="hl sym">.</span><span class="hl kwd">invoke</span><span class="hl sym">(</span><span class="hl kwa">this</span><span class="hl sym">.</span>_servicePath<span class="hl sym">,</span><span class="hl slc">//
Service path</span><span class="hl kwa">this</span><span class="hl sym">.</span>_serviceMethod<span class="hl sym">,</span><span class="hl slc">//
Service method</span><span class="hl kwa">false</span><span class="hl sym">,</span><span class="hl slc">//
use POST (default false)</span> params<span class="hl sym">,</span><span class="hl slc">//
params</span> Function<span class="hl sym">.</span><span class="hl kwd">createDelegate</span><span class="hl sym">(</span><span class="hl kwa">this</span><span class="hl sym">,</span><span class="hl kwa">this</span><span class="hl sym">.</span>_onServiceReply<span class="hl sym">),</span><span class="hl slc">//
on success</span><span class="hl kwa">null</span><span class="hl sym">,</span><span class="hl slc">//
on failure</span><span class="hl kwa">null</span><span class="hl sym">);</span><span class="hl slc">//
additional context</span><span class="hl sym">},</span></pre>
        <p>
The last addition to the script is the <code>this._onServiceReplay</code> handler.
The toolkit uses <code>sender</code> and <code>eventArgs</code> as parameters to the
method. I think they're misnamed, because the object coming in through the <code>sender</code> parameter
is the server reply; a <code>string</code>. At any rate, we fill our help panel with
the contents of the reply.
</p>
        <pre class="code">
          <span class="hl slc">// reply event for the service call</span> _onServiceReply <span class="hl sym">:</span><span class="hl kwa">function</span><span class="hl sym">(</span>sender<span class="hl sym">,</span> eventArgs<span class="hl sym">)
{</span><span class="hl kwc">document</span><span class="hl sym">.</span><span class="hl kwc">getElementById</span><span class="hl sym">(</span><span class="hl kwa">this</span><span class="hl sym">.</span>_helpPanelID<span class="hl sym">).</span><span class="hl kwc">innerHTML</span><span class="hl sym">=</span> sender<span class="hl sym">;</span><span class="hl sym">}</span></pre>
        <p>
At this point, we completed all the code for the extender. All that remains is to
reference this assembly by the website and add our extender to the page.
</p>
        <h4>Using the Help Extender
</h4>
        <p>
Building the extender took a fair handful of code lines, but it all pays off when
we start using the extender in the Web site. Add a reference to the extender project,
and add the folling line to the <code>&lt;system.web&gt;&lt;pages&gt;&lt;controls&gt;</code> element
of the Web.config file:
</p>
        <pre class="code">
          <span class="hl kwa">&lt;add</span> tagPrefix=<span class="hl str">"kbr"</span> namespace=<span class="hl str">"KbrProductions.Web.Extensions"</span> assembly=<span class="hl str">"Extensions"</span>/&gt; </pre>
        <p>
Note that the application will need references to the ASP.NET AJAX assembly and the
AJAX Control Toolkit as well. Add a <code>ScriptManager</code> to the page, and extenders
for the <code>Button</code>, <code>Image</code> and <code>Panel</code>.
</p>
        <pre class="code">
          <span class="hl kwa">&lt;kbr:HelpExtender</span> ID=<span class="hl str">"help1"</span> runat=<span class="hl str">"server"</span> TargetControlID=<span class="hl str">"Button1"</span> HelpContextKey=<span class="hl str">"1"</span> HelpPanelID=<span class="hl str">"HelpPanel"</span> ServiceMethod=<span class="hl str">"GetHelp"</span> /&gt; <span class="hl kwa">&lt;kbr:HelpExtender</span> ID=<span class="hl str">"help2"</span> runat=<span class="hl str">"server"</span> TargetControlID=<span class="hl str">"Image1"</span> HelpContextKey=<span class="hl str">"2"</span> HelpPanelID=<span class="hl str">"HelpPanel"</span> ServiceMethod=<span class="hl str">"GetHelp"</span> /&gt; <span class="hl kwa">&lt;kbr:HelpExtender</span> ID=<span class="hl str">"help3"</span> runat=<span class="hl str">"server"</span> TargetControlID=<span class="hl str">"Panel1"</span> HelpContextKey=<span class="hl str">"3"</span> HelpPanelID=<span class="hl str">"HelpPanel"</span> ServiceMethod=<span class="hl str">"GetHelp"</span> /&gt; </pre>
        <p>
All that remains is to define the Web service that provides our help. We'll inject
an AJAX-friendly service method right into this page. In a more practical application,
the <code>if/else if</code> structure could be replaced with database access, file
IO, or any other data retrieval. All that is required is that the method is static,
takes the appropriate parameters, and returns the expected <code>string</code> result.
</p>
        <pre class="code">
          <span class="hl kwa">&lt;script</span> runat=<span class="hl str">"Server"</span> type=<span class="hl str">"text/C#"</span>&gt; </pre>
        <pre class="code">
          <span class="hl sym">[</span>System<span class="hl sym">.</span>Web<span class="hl sym">.</span>Services<span class="hl sym">.</span>WebMethod<span class="hl sym">]</span><span class="hl sym">[</span>System<span class="hl sym">.</span>Web<span class="hl sym">.</span>Script<span class="hl sym">.</span>Services<span class="hl sym">.</span>ScriptMethod<span class="hl sym">]</span><span class="hl kwa">public
static</span><span class="hl kwb">string</span><span class="hl kwd">GetHelp</span><span class="hl sym">(</span><span class="hl kwb">string</span> helpContextKey<span class="hl sym">)</span><span class="hl sym">{</span><span class="hl kwa">if</span><span class="hl sym">(</span>helpContextKey <span class="hl sym">==</span><span class="hl str">"1"</span><span class="hl sym">)</span><span class="hl kwa">return</span><span class="hl str">"There
is help awaiting you."</span><span class="hl sym">;</span><span class="hl kwa">else
if</span><span class="hl sym">(</span>helpContextKey <span class="hl sym">==</span><span class="hl str">"2"</span><span class="hl sym">)</span><span class="hl kwa">return</span><span class="hl str">"Excellent
clicking, friend!"</span><span class="hl sym">;</span><span class="hl kwa">else</span><span class="hl kwa">return</span><span class="hl str">"There
is no help found for the likes of you."</span><span class="hl sym">;</span><span class="hl sym">}</span></pre>
        <pre class="code">
          <span class="hl kwa">&lt;/script&gt;</span>
        </pre>
        <p>
Running the page now shows that each control has a help cursor. When clicked, JavaScript
issues an asynchronous Web service call which populates a portion of the page with
context-sensitive help. The control extender is finished.
</p>
        <img src="content/attachments/screen.jpg" alt="" />
        <h4>Conclusion
</h4>
        <p>
ASP.NET <acronym title="Asynchronous JavaScript and XML">AJAX</acronym> is an excellent
tool to provide a richer experience to the user by taking advantage of the control
extender model and asynchronous callbacks. With a little footwork, it is possible
to create extenders that add complex behaviors to a variety of server controls, potentially
saving considerable effort down the road. The AJAX Control Toolkit provides classes
that simplify the process of creating your own extenders. Also, because the AJAX Control
Toolkit is open source, you can download the existing control extenders and add behaviors
to them, as well.
</p>
        <p>
Happy Coding!
</p>
        <img width="0" height="0" src="http://www.notesoncode.com/articles/aggbug.ashx?id=ad872df0-da73-44df-9c07-03b38e437995" />
      </body>
      <title>Building a Custom AJAX Control Extender</title>
      <guid isPermaLink="false">http://www.notesoncode.com/articles/PermaLink,guid,ad872df0-da73-44df-9c07-03b38e437995.aspx</guid>
      <link>http://www.notesoncode.com/articles/2007/06/30/BuildingACustomAJAXControlExtender.aspx</link>
      <pubDate>Sat, 30 Jun 2007 15:34:23 GMT</pubDate>
      <description>&lt;p&gt;
Download the source code for this demo &lt;a href="content/attachments/AjaxControlDemo.zip"&gt;here&lt;/a&gt;.
&lt;/p&gt;
&lt;h4&gt;Introduction
&lt;/h4&gt;
&lt;p&gt;
The demand for high quality web interfaces is continually increasing. The movement
towards &lt;em&gt;Web 2.0&lt;/em&gt; places an increasing emphasis in making a web application
look and feel like it were a home desktop application, with all the bells and whistles
attached. Users expect each page they visit to interact with them in a smooth and
natural way.
&lt;/p&gt;
&lt;p&gt;
Asynchronous JavaScript and XML, &lt;acronym title="Asynchronous JavaScript and XML"&gt;AJAX&lt;/acronym&gt;,
is one tool that helps to create this user experience. In a typical scenario, JavaScript
on the page sends and retrieves data from the web server asynchronously, updating
the web page without flicker and with minimal delay. &lt;a href="http://www.google.com/" rel="nofollow"&gt;Google&lt;/a&gt; Inc.'s &lt;a href="http://www.gmail.com/" rel="nofollow"&gt;GMail&lt;/a&gt; is
an example. Each GMail page retrieves content from GMail only a portion at a time,
"on demand". The entire experience is seamless.
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.microsoft.com/"&gt;Microsoft&lt;/a&gt; recently released a framework for &lt;a href="http://ajax.asp.net/"&gt;&lt;acronym title="Asynchronous JavaScript and XML"&gt;AJAX&lt;/acronym&gt;&lt;/a&gt;,
and a corresponding collection of control extenders called the &lt;a href="http://ajax.asp.net/ajaxtoolkit"&gt;AJAX
Control Toolkit&lt;/a&gt;. The toolkit contains several control extenders. An &lt;acronym title="Asynchronous JavaScript and XML"&gt;AJAX&lt;/acronym&gt; control
extender adds &lt;acronym title="Asynchronous JavaScript and XML"&gt;AJAX&lt;/acronym&gt; functionality
to a non-ajax web control. The extender approach can be particularly useful when there
is a requirement to add similar &lt;acronym title="Asynchronous JavaScript and XML"&gt;AJAX&lt;/acronym&gt; behavior
to more than one control type, such as adding behaviors to buttons, images, and panels.
&lt;/p&gt;
&lt;p&gt;
This tutorial introduces the basics of creating a custom &lt;acronym title="Asynchronous JavaScript and XML"&gt;AJAX&lt;/acronym&gt; control
extender. We discuss embedded resources, property decorations (attributes), and client-side
Web service calls.
&lt;/p&gt;
&lt;h4&gt;The Scenario
&lt;/h4&gt;
&lt;p&gt;
Consider a form built for a web application. The form contains several places for
input. From time to time, users flood you with questions about the meaning of each
element. You want to add some context sensitive help to the page to spare yourself
all the most frequently asked questions, saving both time and money.
&lt;/p&gt;
&lt;p&gt;
We'll create a very simple &lt;acronym title="Asynchronous JavaScript and XML"&gt;AJAX&lt;/acronym&gt; control
extender that wraps a server control, such as a &lt;code&gt;Button&lt;/code&gt; or a &lt;code&gt;Label&lt;/code&gt;,
and adds context sensitive help at the click of a mouse. Moreover, the extender will
populate the help with the results of a web service call to separate the content from
the functionality.
&lt;/p&gt;
&lt;h4&gt;Getting Started
&lt;/h4&gt;
&lt;p&gt;
Below is an example of the body of a very simple page. There are three main elements.
On each, we want to add context sensitive help. The fourth element, the &lt;code&gt;Panel&lt;/code&gt; at
the bottom, is a placeholder for our help content.
&lt;/p&gt;
&lt;pre class="code"&gt;
  &lt;span class="hl kwa"&gt;&amp;lt;form&lt;/span&gt; id=&lt;span class="hl str"&gt;&amp;quot;form1&amp;quot;&lt;/span&gt; runat=&lt;span class="hl str"&gt;&amp;quot;server&amp;quot;&lt;/span&gt;&amp;gt; &lt;span class="hl kwa"&gt;&amp;lt;asp:Button&lt;/span&gt; ID=&lt;span class="hl str"&gt;&amp;quot;Button1&amp;quot;&lt;/span&gt; runat=&lt;span class="hl str"&gt;&amp;quot;server&amp;quot;&lt;/span&gt; Text=&lt;span class="hl str"&gt;&amp;quot;Looking
for help...&amp;quot;&lt;/span&gt;/&amp;gt; &lt;span class="hl kwa"&gt;&amp;lt;br&lt;/span&gt; /&amp;gt; &lt;span class="hl kwa"&gt;&amp;lt;br&lt;/span&gt; /&amp;gt; &lt;span class="hl kwa"&gt;&amp;lt;asp:Image&lt;/span&gt; ID=&lt;span class="hl str"&gt;&amp;quot;Image1&amp;quot;&lt;/span&gt; runat=&lt;span class="hl str"&gt;&amp;quot;server&amp;quot;&lt;/span&gt; ImageUrl=&lt;span class="hl str"&gt;&amp;quot;~/flower.jpg&amp;quot;&lt;/span&gt; /&amp;gt; &lt;span class="hl kwa"&gt;&amp;lt;br&lt;/span&gt; /&amp;gt; &lt;span class="hl kwa"&gt;&amp;lt;br&lt;/span&gt; /&amp;gt; &lt;span class="hl kwa"&gt;&amp;lt;asp:Panel&lt;/span&gt; ID=&lt;span class="hl str"&gt;&amp;quot;Panel1&amp;quot;&lt;/span&gt; runat=&lt;span class="hl str"&gt;&amp;quot;server&amp;quot;&lt;/span&gt;&amp;gt;
This is the content of the panel.&lt;span class="hl kwa"&gt;&amp;lt;br&lt;/span&gt; /&amp;gt; If you would
like to find help, kindly click among this text.&lt;span class="hl kwa"&gt;&amp;lt;br&lt;/span&gt; /&amp;gt;
Good luck! &lt;span class="hl kwa"&gt;&amp;lt;/asp:Panel&amp;gt;&lt;/span&gt; &lt;span class="hl kwa"&gt;&amp;lt;br&lt;/span&gt; /&amp;gt; &lt;span class="hl kwa"&gt;&amp;lt;br&lt;/span&gt; /&amp;gt; &lt;span class="hl kwa"&gt;&amp;lt;asp:Panel&lt;/span&gt; ID=&lt;span class="hl str"&gt;&amp;quot;HelpPanel&amp;quot;&lt;/span&gt; runat=&lt;span class="hl str"&gt;&amp;quot;server&amp;quot;&lt;/span&gt; /&amp;gt; &lt;span class="hl kwa"&gt;&amp;lt;br&lt;/span&gt; /&amp;gt; &lt;span class="hl kwa"&gt;&amp;lt;br&lt;/span&gt; /&amp;gt; &lt;span class="hl kwa"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt; &lt;/pre&gt;
&lt;p&gt;
To make our control extender consumable from any website, we'll compile the extender
into a separate assembly. To do this, first make sure that the extender templates
are installed. Download the &lt;acronym title="Asynchronous JavaScript and XML"&gt;AJAX&lt;/acronym&gt; control
toolkit from &lt;a href="http://ajax.asp.net" rel="nofollow"&gt;http://ajax.asp.net&lt;/a&gt;,
extract the files into the directory of choice, and execute the .vsi installers located
in the archive at &lt;strong&gt;AjaxControlExtender\AjaxControlExtender.vsi&lt;/strong&gt;. Once
this is installed, add the new extender project to your Visual Studio solution by
right clicking on the solution and selecting Add -&gt; New Project, or selecting File
-&gt; Add -&gt; New Project from the menu.
&lt;/p&gt;
&lt;img src="content/attachments/addnewproj.jpg" alt="" /&gt; 
&lt;p&gt;
Select &lt;strong&gt;ASP.NET AJAX Control Project&lt;/strong&gt; from the templates.
&lt;/p&gt;
&lt;img src="content/attachments/ajaxproject.gif" alt="" /&gt; 
&lt;p&gt;
Delete the default &lt;code&gt;.cs&lt;/code&gt; and &lt;code&gt;.js&lt;/code&gt; files, and create a directory, &lt;code&gt;Help&lt;/code&gt; to
hold the new control. Right click on the folder, select Add -&gt; New Item, and select &lt;strong&gt;ASP.NET
AJAX Extender Control&lt;/strong&gt; from the templates. Name the control "Help", since
the convention of "HelpExtender" is added by default.
&lt;/p&gt;
&lt;img src="content/attachments/ajaxcontrol.jpg" alt="" /&gt; 
&lt;p&gt;
We now have the basic file structure for the control.
&lt;/p&gt;
&lt;h4&gt;Configuring the Namespaces
&lt;/h4&gt;
&lt;p&gt;
It is important to give some thought to the namespace conventions for your control.
There are three namespaces of immediate concern: 
&lt;ol&gt;
&lt;li&gt;
The namespace of your server code&lt;/li&gt;
&lt;li&gt;
The namespace of your client JavaScript&lt;/li&gt;
&lt;li&gt;
The default namespace of your assembly&lt;/li&gt;
&lt;/ol&gt;
&gt;
&lt;p&gt;
Adjusting the namespace of server code is plain and direct. I chose &lt;code&gt;KbrProductions.Web.Extensions&lt;/code&gt;,
after the pattern set by Microsoft's &lt;code&gt;System.Web.Extensions&lt;/code&gt;. The client
namespace is adjusted in the &lt;code&gt;.js&lt;/code&gt; file. For this project the client namespace
is &lt;code&gt;KbrProductions.Ajax&lt;/code&gt;. A simple search and replace can fix the handful
of references. Finally, the default namespace of the assembly can be configured by
right clicking on the project file, selecting Properties, and editing the namespace
in the Application tab. This namespace is important because it influences embedded
resources.
&lt;/p&gt;
&lt;img src="content/attachments/projproperties.jpg" alt="" /&gt; 
&lt;p&gt;
For the JavaScript file to be consumable by the website, we must include it as a resource
to the project assembly. Do this by selecting the file in Solution Explorer, viewing
its properties, and setting the Build Action attribute to Embedded Resource.
&lt;/p&gt;
&lt;img src="content/attachments/embed.jpg" alt="" /&gt; 
&lt;p&gt;
Now visit the &lt;code&gt;HelpExtender.cs&lt;/code&gt; file. Edit the assembly attribute to read:
&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span class="hl sym"&gt;[&lt;/span&gt;assembly&lt;span class="hl sym"&gt;:&lt;/span&gt; System&lt;span class="hl sym"&gt;.&lt;/span&gt;Web&lt;span class="hl sym"&gt;.&lt;/span&gt;UI&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;WebResource&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt; &lt;span class="hl str"&gt;&amp;quot;KbrProductions.Web.Extensions.Help.HelpBehavior.js&amp;quot;&lt;/span&gt;&lt;span class="hl sym"&gt;,&lt;/span&gt; &lt;span class="hl str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&lt;span class="hl sym"&gt;)]&lt;/span&gt; &lt;/pre&gt;
&lt;p&gt;
The first parameter is a resource path for the javascript file. The naming convention
for the path is: [Assembly Namespace][.directory][.FileName]. Remember, the assembly
namespace is the default namespace set in the project properties. For the directory,
use dots (.) to separate folders instead of backslashes. Misconfiguring this line
is the common cause of the following web page error:
&lt;/p&gt;
&lt;blockquote&gt;Assembly 'Extensions, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'
contains a Web resource with name 'Extensions.Help.HelpBehavior.js', but does not
contain an embedded resource with name 'Extensions.Help.HelpBehavior.js'.&lt;/blockquote&gt; 
&lt;p&gt;
When in doubt, fire up &lt;acronym title="Intermediate Language Disassembler"&gt;ILDASM&lt;/acronym&gt; and
view the contents of the control assembly. The manifest contains the proper path for
the JavaScript file on a &lt;code&gt;.mresource&lt;/code&gt; line.
&lt;/p&gt;
&lt;img src="content/attachments/ildasm.jpg" alt="" /&gt; 
&lt;p&gt;
The extender class includes the JavaScript file by means of a &lt;code&gt;ClientScriptResource&lt;/code&gt; decoration.
Modify the decoration as shown below, where the first string indicates the client
class name, and the second string specifies the resource exactly as specified in the
assembly attribute earlier in the page.
&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span class="hl sym"&gt;[&lt;/span&gt;&lt;span class="hl kwd"&gt;ClientScriptResource&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt; &lt;span class="hl str"&gt;&amp;quot;KbrProductions.Ajax.HelpBehavior&amp;quot;&lt;/span&gt;&lt;span class="hl sym"&gt;,&lt;/span&gt; &lt;span class="hl str"&gt;&amp;quot;KbrProductions.Web.Extensions.Help.HelpBehavior.js&amp;quot;&lt;/span&gt;&lt;span class="hl sym"&gt;)]&lt;/span&gt; &lt;/pre&gt;
&lt;p&gt;
At this point, the namespaces of the control assembly should be configured.
&lt;/p&gt;
&lt;h4&gt;Server-Side Extender Properties
&lt;/h4&gt;
&lt;p&gt;
Next, we'll specify the properties that will be available as attributes to our extender
markup. Because we inherit from &lt;code&gt;ExtenderControlBase&lt;/code&gt;, we already have
a &lt;code&gt;TargetControlID&lt;/code&gt; property, which we can use to specify the control we
want to extend.
&lt;/p&gt;
&lt;p&gt;
We also want to specify the control that will contain the contents of our help. We
decorate the property with the &lt;code&gt;IDReferenceProperty&lt;/code&gt; attribute to enable
the extender to automatically resolve the specified &lt;code&gt;ID&lt;/code&gt; into a &lt;code&gt;ClientID&lt;/code&gt;.
&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span class="hl slc"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt; &lt;span class="hl slc"&gt;///
ID of the control that will contain the help content.&lt;/span&gt; &lt;span class="hl slc"&gt;///
&amp;lt;/summary&amp;gt;&lt;/span&gt; &lt;span class="hl sym"&gt;[&lt;/span&gt;ExtenderControlProperty&lt;span class="hl sym"&gt;]&lt;/span&gt; &lt;span class="hl sym"&gt;[&lt;/span&gt;&lt;span class="hl kwd"&gt;DefaultValue&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="hl sym"&gt;)]&lt;/span&gt; &lt;span class="hl sym"&gt;[&lt;/span&gt;&lt;span class="hl kwd"&gt;IDReferenceProperty&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl kwd"&gt;typeof&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;WebControl&lt;span class="hl sym"&gt;))]&lt;/span&gt; &lt;span class="hl sym"&gt;[&lt;/span&gt;&lt;span class="hl kwd"&gt;ClientPropertyName&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl str"&gt;&amp;quot;helpPanelID&amp;quot;&lt;/span&gt;&lt;span class="hl sym"&gt;)]&lt;/span&gt; &lt;span class="hl kwa"&gt;public&lt;/span&gt; &lt;span class="hl kwb"&gt;string&lt;/span&gt; HelpPanelID &lt;span class="hl sym"&gt;{&lt;/span&gt; &lt;span class="hl kwa"&gt;get&lt;/span&gt; &lt;span class="hl sym"&gt;{&lt;/span&gt; &lt;span class="hl kwa"&gt;return&lt;/span&gt; &lt;span class="hl kwd"&gt;GetPropertyValue&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl str"&gt;&amp;quot;HelpPanelID&amp;quot;&lt;/span&gt;&lt;span class="hl sym"&gt;,&lt;/span&gt; &lt;span class="hl str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="hl sym"&gt;);
}&lt;/span&gt; &lt;span class="hl kwa"&gt;set&lt;/span&gt; &lt;span class="hl sym"&gt;{&lt;/span&gt; &lt;span class="hl kwd"&gt;SetPropertyValue&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl str"&gt;&amp;quot;HelpPanelID&amp;quot;&lt;/span&gt;&lt;span class="hl sym"&gt;,&lt;/span&gt; &lt;span class="hl kwa"&gt;value&lt;/span&gt;&lt;span class="hl sym"&gt;);
}&lt;/span&gt; &lt;span class="hl sym"&gt;}&lt;/span&gt; &lt;/pre&gt;
&lt;p&gt;
Next, we'll build properties to define the location of a Web service that provides
the text for the context-sensitive help. We decorate this property as a &lt;code&gt;UrlProperty&lt;/code&gt;,
which provides automatic resolving of server-relative URLs, that is, any URL starting
with "~/". We also decorate it with a &lt;code&gt;TypeConverter&lt;/code&gt; to handle some Web
service specific url handling.
&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span class="hl slc"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt; &lt;span class="hl slc"&gt;///
Path to the webservice that the extender will pull the images from.&lt;/span&gt; &lt;span class="hl slc"&gt;///
&amp;lt;/summary&amp;gt;&lt;/span&gt; &lt;span class="hl sym"&gt;[&lt;/span&gt;&lt;span class="hl kwd"&gt;UrlProperty&lt;/span&gt;&lt;span class="hl sym"&gt;()]&lt;/span&gt; &lt;span class="hl sym"&gt;[&lt;/span&gt;&lt;span class="hl kwd"&gt;ExtenderControlProperty&lt;/span&gt;&lt;span class="hl sym"&gt;()]&lt;/span&gt; &lt;span class="hl sym"&gt;[&lt;/span&gt;&lt;span class="hl kwd"&gt;TypeConverter&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl kwd"&gt;typeof&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;ServicePathConverter&lt;span class="hl sym"&gt;))]&lt;/span&gt; &lt;span class="hl sym"&gt;[&lt;/span&gt;&lt;span class="hl kwd"&gt;ClientPropertyName&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl str"&gt;&amp;quot;servicePath&amp;quot;&lt;/span&gt;&lt;span class="hl sym"&gt;)]&lt;/span&gt; &lt;span class="hl kwa"&gt;public&lt;/span&gt; &lt;span class="hl kwb"&gt;string&lt;/span&gt; ServicePath &lt;span class="hl sym"&gt;{&lt;/span&gt; &lt;span class="hl kwa"&gt;get&lt;/span&gt; &lt;span class="hl sym"&gt;{&lt;/span&gt; &lt;span class="hl kwa"&gt;return&lt;/span&gt; &lt;span class="hl kwd"&gt;GetPropertyValue&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl str"&gt;&amp;quot;ServicePath&amp;quot;&lt;/span&gt;&lt;span class="hl sym"&gt;,&lt;/span&gt; &lt;span class="hl str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="hl sym"&gt;);
}&lt;/span&gt; &lt;span class="hl kwa"&gt;set&lt;/span&gt; &lt;span class="hl sym"&gt;{&lt;/span&gt; &lt;span class="hl kwd"&gt;SetPropertyValue&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl str"&gt;&amp;quot;ServicePath&amp;quot;&lt;/span&gt;&lt;span class="hl sym"&gt;,&lt;/span&gt; &lt;span class="hl kwa"&gt;value&lt;/span&gt;&lt;span class="hl sym"&gt;);
}&lt;/span&gt; &lt;span class="hl sym"&gt;}&lt;/span&gt; &lt;/pre&gt;
&lt;p&gt;
Next we add a required property to define which method should be called.
&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span class="hl slc"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt; &lt;span class="hl slc"&gt;///
The webservice method that will be called to supply help.&lt;/span&gt; &lt;span class="hl slc"&gt;///
&amp;lt;/summary&amp;gt;&lt;/span&gt; &lt;span class="hl sym"&gt;[&lt;/span&gt;ExtenderControlProperty&lt;span class="hl sym"&gt;]&lt;/span&gt; &lt;span class="hl sym"&gt;[&lt;/span&gt;RequiredProperty&lt;span class="hl sym"&gt;]&lt;/span&gt; &lt;span class="hl sym"&gt;[&lt;/span&gt;&lt;span class="hl kwd"&gt;DefaultValue&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="hl sym"&gt;)]&lt;/span&gt; &lt;span class="hl sym"&gt;[&lt;/span&gt;&lt;span class="hl kwd"&gt;ClientPropertyName&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl str"&gt;&amp;quot;serviceMethod&amp;quot;&lt;/span&gt;&lt;span class="hl sym"&gt;)]&lt;/span&gt; &lt;span class="hl kwa"&gt;public&lt;/span&gt; &lt;span class="hl kwb"&gt;string&lt;/span&gt; ServiceMethod &lt;span class="hl sym"&gt;{&lt;/span&gt; &lt;span class="hl kwa"&gt;get&lt;/span&gt; &lt;span class="hl sym"&gt;{&lt;/span&gt; &lt;span class="hl kwa"&gt;return&lt;/span&gt; &lt;span class="hl kwd"&gt;GetPropertyValue&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl str"&gt;&amp;quot;ServiceMethod&amp;quot;&lt;/span&gt;&lt;span class="hl sym"&gt;,&lt;/span&gt; &lt;span class="hl str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="hl sym"&gt;);
}&lt;/span&gt; &lt;span class="hl kwa"&gt;set&lt;/span&gt; &lt;span class="hl sym"&gt;{&lt;/span&gt; &lt;span class="hl kwd"&gt;SetPropertyValue&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl str"&gt;&amp;quot;ServiceMethod&amp;quot;&lt;/span&gt;&lt;span class="hl sym"&gt;,&lt;/span&gt; &lt;span class="hl kwa"&gt;value&lt;/span&gt;&lt;span class="hl sym"&gt;);
}&lt;/span&gt; &lt;span class="hl sym"&gt;}&lt;/span&gt; &lt;/pre&gt;
&lt;p&gt;
And, finally, we add a property to define a parameter for the Web service call. We
could treat this parameter as a key to determine which piece of help to return from
the service.
&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span class="hl slc"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt; &lt;span class="hl slc"&gt;///
Context key to pass to the service method to get help text.&lt;/span&gt; &lt;span class="hl slc"&gt;///
&amp;lt;/summary&amp;gt;&lt;/span&gt; &lt;span class="hl sym"&gt;[&lt;/span&gt;ExtenderControlProperty&lt;span class="hl sym"&gt;]&lt;/span&gt; &lt;span class="hl sym"&gt;[&lt;/span&gt;&lt;span class="hl kwd"&gt;DefaultValue&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="hl sym"&gt;)]&lt;/span&gt; &lt;span class="hl sym"&gt;[&lt;/span&gt;&lt;span class="hl kwd"&gt;ClientPropertyName&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl str"&gt;&amp;quot;helpContextKey&amp;quot;&lt;/span&gt;&lt;span class="hl sym"&gt;)]&lt;/span&gt; &lt;span class="hl kwa"&gt;public&lt;/span&gt; &lt;span class="hl kwb"&gt;string&lt;/span&gt; HelpContextKey &lt;span class="hl sym"&gt;{&lt;/span&gt; &lt;span class="hl kwa"&gt;get&lt;/span&gt; &lt;span class="hl sym"&gt;{&lt;/span&gt; &lt;span class="hl kwa"&gt;return&lt;/span&gt; &lt;span class="hl kwd"&gt;GetPropertyValue&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl str"&gt;&amp;quot;HelpContextKey&amp;quot;&lt;/span&gt;&lt;span class="hl sym"&gt;,&lt;/span&gt; &lt;span class="hl str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="hl sym"&gt;);
}&lt;/span&gt; &lt;span class="hl kwa"&gt;set&lt;/span&gt; &lt;span class="hl sym"&gt;{&lt;/span&gt; &lt;span class="hl kwd"&gt;SetPropertyValue&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl str"&gt;&amp;quot;HelpContextKey&amp;quot;&lt;/span&gt;&lt;span class="hl sym"&gt;,&lt;/span&gt; &lt;span class="hl kwa"&gt;value&lt;/span&gt;&lt;span class="hl sym"&gt;);
}&lt;/span&gt; &lt;span class="hl sym"&gt;}&lt;/span&gt; &lt;/pre&gt;
&lt;p&gt;
The next step is to provide a client-side equivalent interface to these properties.
&lt;/p&gt;
&lt;h4&gt;Client-Side Extender Properties
&lt;/h4&gt;
&lt;p&gt;
Basic handling of each property from JavaScript is made extremely simple due to the
AJAX Control Toolkit. All that is required is to add variable declarations to the
constructor function, and add get/set functions to the object prototype. It is important
to note that the property names for the get and set functions are case sensitive and
should reflect the &lt;code&gt;ClientPropertyName&lt;/code&gt; configured in the server-side extender
code. Additional utility variables can be added to the constructor function as well.
&lt;/p&gt;
&lt;pre class="code"&gt;KbrProductions&lt;span class="hl sym"&gt;.&lt;/span&gt;Ajax&lt;span class="hl sym"&gt;.&lt;/span&gt;HelpBehavior &lt;span class="hl sym"&gt;=&lt;/span&gt; &lt;span class="hl kwa"&gt;function&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;element&lt;span class="hl sym"&gt;)
{&lt;/span&gt; KbrProductions&lt;span class="hl sym"&gt;.&lt;/span&gt;Ajax&lt;span class="hl sym"&gt;.&lt;/span&gt;HelpBehavior&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;initializeBase&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;,
[&lt;/span&gt;element&lt;span class="hl sym"&gt;]);&lt;/span&gt; &lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;_helpContextKey &lt;span class="hl sym"&gt;=&lt;/span&gt; &lt;span class="hl kwa"&gt;null&lt;/span&gt;&lt;span class="hl sym"&gt;;&lt;/span&gt; &lt;span class="hl slc"&gt;//
HelpContextKey property&lt;/span&gt; &lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;_serviceMethod &lt;span class="hl sym"&gt;=&lt;/span&gt; &lt;span class="hl kwa"&gt;null&lt;/span&gt;&lt;span class="hl sym"&gt;;&lt;/span&gt; &lt;span class="hl slc"&gt;//
ServiceMethod property&lt;/span&gt; &lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;_servicePath &lt;span class="hl sym"&gt;=&lt;/span&gt; &lt;span class="hl kwa"&gt;null&lt;/span&gt;&lt;span class="hl sym"&gt;;&lt;/span&gt; &lt;span class="hl slc"&gt;//
ServicePath property&lt;/span&gt; &lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;_helpPanelID &lt;span class="hl sym"&gt;=&lt;/span&gt; &lt;span class="hl kwa"&gt;null&lt;/span&gt;&lt;span class="hl sym"&gt;;&lt;/span&gt; &lt;span class="hl slc"&gt;//
HelpPanelID property&lt;/span&gt; &lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;_helpPanel &lt;span class="hl sym"&gt;=&lt;/span&gt; &lt;span class="hl kwa"&gt;null&lt;/span&gt;&lt;span class="hl sym"&gt;;&lt;/span&gt; &lt;span class="hl slc"&gt;//
HelpPanel element&lt;/span&gt; &lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;_clickHandler &lt;span class="hl sym"&gt;=&lt;/span&gt; &lt;span class="hl kwa"&gt;null&lt;/span&gt;&lt;span class="hl sym"&gt;;&lt;/span&gt; &lt;span class="hl slc"&gt;//
Click Event handler for the extended control&lt;/span&gt; &lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;_targetElement &lt;span class="hl sym"&gt;=&lt;/span&gt; &lt;span class="hl kwa"&gt;null&lt;/span&gt;&lt;span class="hl sym"&gt;;&lt;/span&gt; &lt;span class="hl slc"&gt;//
Element of the extended control&lt;/span&gt; &lt;span class="hl sym"&gt;}&lt;/span&gt; KbrProductions&lt;span class="hl sym"&gt;.&lt;/span&gt;Ajax&lt;span class="hl sym"&gt;.&lt;/span&gt;HelpBehavior&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwa"&gt;prototype&lt;/span&gt; &lt;span class="hl sym"&gt;=
{&lt;/span&gt; &lt;span class="hl slc"&gt;// ...&lt;/span&gt; &lt;span class="hl slc"&gt;// extended properties&lt;/span&gt; get_serviceMethod &lt;span class="hl sym"&gt;:&lt;/span&gt; &lt;span class="hl kwa"&gt;function&lt;/span&gt;&lt;span class="hl sym"&gt;()
{&lt;/span&gt; &lt;span class="hl kwa"&gt;return this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;_serviceMethod&lt;span class="hl sym"&gt;;
},&lt;/span&gt; set_serviceMethod &lt;span class="hl sym"&gt;:&lt;/span&gt; &lt;span class="hl kwa"&gt;function&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl kwc"&gt;value&lt;/span&gt;&lt;span class="hl sym"&gt;)
{&lt;/span&gt; &lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;_serviceMethod &lt;span class="hl sym"&gt;=&lt;/span&gt; &lt;span class="hl kwc"&gt;value&lt;/span&gt;&lt;span class="hl sym"&gt;;
},&lt;/span&gt; get_servicePath &lt;span class="hl sym"&gt;:&lt;/span&gt; &lt;span class="hl kwa"&gt;function&lt;/span&gt;&lt;span class="hl sym"&gt;()
{&lt;/span&gt; &lt;span class="hl kwa"&gt;return this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;_servicePath&lt;span class="hl sym"&gt;;
},&lt;/span&gt; set_servicePath &lt;span class="hl sym"&gt;:&lt;/span&gt; &lt;span class="hl kwa"&gt;function&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl kwc"&gt;value&lt;/span&gt;&lt;span class="hl sym"&gt;)
{&lt;/span&gt; &lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;_servicePath &lt;span class="hl sym"&gt;=&lt;/span&gt; &lt;span class="hl kwc"&gt;value&lt;/span&gt;&lt;span class="hl sym"&gt;;
},&lt;/span&gt; get_helpContextKey &lt;span class="hl sym"&gt;:&lt;/span&gt; &lt;span class="hl kwa"&gt;function&lt;/span&gt;&lt;span class="hl sym"&gt;()
{&lt;/span&gt; &lt;span class="hl kwa"&gt;return this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;_helpContextKey&lt;span class="hl sym"&gt;;
},&lt;/span&gt; set_helpContextKey &lt;span class="hl sym"&gt;:&lt;/span&gt; &lt;span class="hl kwa"&gt;function&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl kwc"&gt;value&lt;/span&gt;&lt;span class="hl sym"&gt;)
{&lt;/span&gt; &lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;_helpContextKey &lt;span class="hl sym"&gt;=&lt;/span&gt; &lt;span class="hl kwc"&gt;value&lt;/span&gt;&lt;span class="hl sym"&gt;;
},&lt;/span&gt; get_helpPanelID &lt;span class="hl sym"&gt;:&lt;/span&gt; &lt;span class="hl kwa"&gt;function&lt;/span&gt;&lt;span class="hl sym"&gt;()
{&lt;/span&gt; &lt;span class="hl kwa"&gt;return this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;_helpPanelID&lt;span class="hl sym"&gt;;
},&lt;/span&gt; set_helpPanelID &lt;span class="hl sym"&gt;:&lt;/span&gt; &lt;span class="hl kwa"&gt;function&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl kwc"&gt;value&lt;/span&gt;&lt;span class="hl sym"&gt;)
{&lt;/span&gt; &lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;_helpPanelID &lt;span class="hl sym"&gt;=&lt;/span&gt; &lt;span class="hl kwc"&gt;value&lt;/span&gt;&lt;span class="hl sym"&gt;;
}&lt;/span&gt; &lt;span class="hl sym"&gt;}&lt;/span&gt; &lt;/pre&gt;
&lt;h4&gt;Fleshing out the Client Behavior
&lt;/h4&gt;
&lt;p&gt;
All that remains to complete our extender is to implement the client behavior. To
provide feedback to the user that a control contains help, change the mouse cursor
of the extended element. The object prototype's initialize method is a good place
to do this.
&lt;/p&gt;
&lt;pre class="code"&gt;initialize &lt;span class="hl sym"&gt;:&lt;/span&gt; &lt;span class="hl kwa"&gt;function&lt;/span&gt;&lt;span class="hl sym"&gt;()
{&lt;/span&gt; KbrProductions&lt;span class="hl sym"&gt;.&lt;/span&gt;Ajax&lt;span class="hl sym"&gt;.&lt;/span&gt;HelpBehavior&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;callBaseMethod&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;,&lt;/span&gt; &lt;span class="hl str"&gt;'initialize'&lt;/span&gt;&lt;span class="hl sym"&gt;);&lt;/span&gt; &lt;span class="hl slc"&gt;//
Apply the CSS cursor style, &amp;quot;help&amp;quot;&lt;/span&gt; &lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;_targetElement &lt;span class="hl sym"&gt;=&lt;/span&gt; &lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;get_element&lt;/span&gt;&lt;span class="hl sym"&gt;();&lt;/span&gt; &lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;_targetElement&lt;span class="hl sym"&gt;.&lt;/span&gt;style&lt;span class="hl sym"&gt;.&lt;/span&gt;cursor &lt;span class="hl sym"&gt;=&lt;/span&gt; &lt;span class="hl str"&gt;&amp;quot;help&amp;quot;&lt;/span&gt;&lt;span class="hl sym"&gt;;&lt;/span&gt; &lt;span class="hl slc"&gt;//
...&lt;/span&gt; &lt;/pre&gt;
&lt;p&gt;
Next, wire up an event handler in the initialize function to handle the click event
of the target element. Use the Function.createDelegate method to create the handler.
This ensures that multiple handlers can potentially be attached to the element without
conflicting.
&lt;/p&gt;
&lt;pre class="code"&gt;    &lt;span class="hl slc"&gt;// Attach an event handler to the click
event of the element&lt;/span&gt; &lt;span class="hl kwa"&gt;if&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;_targetElement&lt;span class="hl sym"&gt;)
{&lt;/span&gt; &lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;_clickHandler &lt;span class="hl sym"&gt;=&lt;/span&gt; Function&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;createDelegate&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;,&lt;/span&gt; &lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;_onClick&lt;span class="hl sym"&gt;);&lt;/span&gt; $&lt;span class="hl kwd"&gt;addHandler&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;_targetElement&lt;span class="hl sym"&gt;,&lt;/span&gt; &lt;span class="hl str"&gt;'click'&lt;/span&gt;&lt;span class="hl sym"&gt;,&lt;/span&gt; &lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;_clickHandler&lt;span class="hl sym"&gt;);&lt;/span&gt; &lt;span class="hl sym"&gt;}&lt;/span&gt; &lt;/pre&gt;
&lt;p&gt;
Add functionality to the dispose method to clean up the event handler. This is good
practice to keep our memory clean.
&lt;/p&gt;
&lt;pre class="code"&gt;dispose &lt;span class="hl sym"&gt;:&lt;/span&gt; &lt;span class="hl kwa"&gt;function&lt;/span&gt;&lt;span class="hl sym"&gt;()
{&lt;/span&gt; &lt;span class="hl slc"&gt;// Remove the event handler from the element if attached.&lt;/span&gt; &lt;span class="hl kwa"&gt;if&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;_clickHandler&lt;span class="hl sym"&gt;)
{&lt;/span&gt; $&lt;span class="hl kwd"&gt;removeHandler&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;_targetElement&lt;span class="hl sym"&gt;,&lt;/span&gt; &lt;span class="hl str"&gt;'click'&lt;/span&gt;&lt;span class="hl sym"&gt;,&lt;/span&gt; &lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;_clickHandler&lt;span class="hl sym"&gt;);&lt;/span&gt; &lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;_clickHandler &lt;span class="hl sym"&gt;=&lt;/span&gt; &lt;span class="hl kwa"&gt;null&lt;/span&gt;&lt;span class="hl sym"&gt;;&lt;/span&gt; &lt;span class="hl sym"&gt;}&lt;/span&gt; KbrProductions&lt;span class="hl sym"&gt;.&lt;/span&gt;Ajax&lt;span class="hl sym"&gt;.&lt;/span&gt;HelpBehavior&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;callBaseMethod&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;,&lt;/span&gt; &lt;span class="hl str"&gt;'dispose'&lt;/span&gt;&lt;span class="hl sym"&gt;);&lt;/span&gt; &lt;span class="hl sym"&gt;},&lt;/span&gt; &lt;/pre&gt;
&lt;p&gt;
We now create the &lt;code&gt;this._onClick&lt;/code&gt; function to handle the mouse click. We
first implement a few lines to prevent any full-page postback that might occur. Parameters
to the service method should be prepared as a dictionary key-value pair. We then can
invoke the method using the ASP.NET AJAX &lt;code&gt;Sys.Net.WebServiceProxy.invoke&lt;/code&gt; method.
The method has seven parameters: 
&lt;ol&gt;
&lt;li&gt;
The path to the Web service.&lt;/li&gt;
&lt;li&gt;
The method to invoke.&lt;/li&gt;
&lt;li&gt;
A parameter to indicate whether the call should use HTTP POST. For security reasons,
this defaults to &lt;code&gt;false&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
The parameters for the method.&lt;/li&gt;
&lt;li&gt;
An event handler to be called when the service call returns successfully.&lt;/li&gt;
&lt;li&gt;
An event handler to be called if the service call fails.&lt;/li&gt;
&lt;li&gt;
Any JavaScript structure to pass to the event handler. This is a place holder if you
want to send more than the defaults.&lt;/li&gt;
&lt;/ol&gt;
&gt;
&lt;pre class="code"&gt;&lt;span class="hl slc"&gt;// click event for the extended element&lt;/span&gt; _onClick &lt;span class="hl sym"&gt;:&lt;/span&gt; &lt;span class="hl kwa"&gt;function&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;e&lt;span class="hl sym"&gt;)
{&lt;/span&gt; &lt;span class="hl slc"&gt;// prevent post back.&lt;/span&gt; e&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;preventDefault&lt;/span&gt;&lt;span class="hl sym"&gt;();&lt;/span&gt; e&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;stopPropagation&lt;/span&gt;&lt;span class="hl sym"&gt;();&lt;/span&gt; &lt;span class="hl slc"&gt;//
prepare parameters, if necessary&lt;/span&gt; &lt;span class="hl kwa"&gt;var&lt;/span&gt; params &lt;span class="hl sym"&gt;=&lt;/span&gt; &lt;span class="hl kwa"&gt;null&lt;/span&gt;&lt;span class="hl sym"&gt;;&lt;/span&gt; &lt;span class="hl kwa"&gt;if&lt;/span&gt; &lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;_helpContextKey&lt;span class="hl sym"&gt;)
{&lt;/span&gt; params &lt;span class="hl sym"&gt;= {&lt;/span&gt; &lt;span class="hl str"&gt;'helpContextKey'&lt;/span&gt; &lt;span class="hl sym"&gt;:&lt;/span&gt; &lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;_helpContextKey &lt;span class="hl sym"&gt;};&lt;/span&gt; &lt;span class="hl sym"&gt;}&lt;/span&gt; &lt;span class="hl slc"&gt;//
Invoke the web service&lt;/span&gt; Sys&lt;span class="hl sym"&gt;.&lt;/span&gt;Net&lt;span class="hl sym"&gt;.&lt;/span&gt;WebServiceProxy&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;invoke&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt; &lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;_servicePath&lt;span class="hl sym"&gt;,&lt;/span&gt; &lt;span class="hl slc"&gt;//
Service path&lt;/span&gt; &lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;_serviceMethod&lt;span class="hl sym"&gt;,&lt;/span&gt; &lt;span class="hl slc"&gt;//
Service method&lt;/span&gt; &lt;span class="hl kwa"&gt;false&lt;/span&gt;&lt;span class="hl sym"&gt;,&lt;/span&gt; &lt;span class="hl slc"&gt;//
use POST (default false)&lt;/span&gt; params&lt;span class="hl sym"&gt;,&lt;/span&gt; &lt;span class="hl slc"&gt;//
params&lt;/span&gt; Function&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwd"&gt;createDelegate&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;,&lt;/span&gt; &lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;_onServiceReply&lt;span class="hl sym"&gt;),&lt;/span&gt; &lt;span class="hl slc"&gt;//
on success&lt;/span&gt; &lt;span class="hl kwa"&gt;null&lt;/span&gt;&lt;span class="hl sym"&gt;,&lt;/span&gt; &lt;span class="hl slc"&gt;//
on failure&lt;/span&gt; &lt;span class="hl kwa"&gt;null&lt;/span&gt;&lt;span class="hl sym"&gt;);&lt;/span&gt; &lt;span class="hl slc"&gt;//
additional context&lt;/span&gt; &lt;span class="hl sym"&gt;},&lt;/span&gt; &lt;/pre&gt;
&lt;p&gt;
The last addition to the script is the &lt;code&gt;this._onServiceReplay&lt;/code&gt; handler.
The toolkit uses &lt;code&gt;sender&lt;/code&gt; and &lt;code&gt;eventArgs&lt;/code&gt; as parameters to the
method. I think they're misnamed, because the object coming in through the &lt;code&gt;sender&lt;/code&gt; parameter
is the server reply; a &lt;code&gt;string&lt;/code&gt;. At any rate, we fill our help panel with
the contents of the reply.
&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span class="hl slc"&gt;// reply event for the service call&lt;/span&gt; _onServiceReply &lt;span class="hl sym"&gt;:&lt;/span&gt; &lt;span class="hl kwa"&gt;function&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;sender&lt;span class="hl sym"&gt;,&lt;/span&gt; eventArgs&lt;span class="hl sym"&gt;)
{&lt;/span&gt; &lt;span class="hl kwc"&gt;document&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;&lt;span class="hl kwc"&gt;getElementById&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl kwa"&gt;this&lt;/span&gt;&lt;span class="hl sym"&gt;.&lt;/span&gt;_helpPanelID&lt;span class="hl sym"&gt;).&lt;/span&gt;&lt;span class="hl kwc"&gt;innerHTML&lt;/span&gt; &lt;span class="hl sym"&gt;=&lt;/span&gt; sender&lt;span class="hl sym"&gt;;&lt;/span&gt; &lt;span class="hl sym"&gt;}&lt;/span&gt; &lt;/pre&gt;
&lt;p&gt;
At this point, we completed all the code for the extender. All that remains is to
reference this assembly by the website and add our extender to the page.
&lt;/p&gt;
&lt;h4&gt;Using the Help Extender
&lt;/h4&gt;
&lt;p&gt;
Building the extender took a fair handful of code lines, but it all pays off when
we start using the extender in the Web site. Add a reference to the extender project,
and add the folling line to the &lt;code&gt;&amp;lt;system.web&amp;gt;&amp;lt;pages&amp;gt;&amp;lt;controls&amp;gt;&lt;/code&gt; element
of the Web.config file:
&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span class="hl kwa"&gt;&amp;lt;add&lt;/span&gt; tagPrefix=&lt;span class="hl str"&gt;&amp;quot;kbr&amp;quot;&lt;/span&gt; namespace=&lt;span class="hl str"&gt;&amp;quot;KbrProductions.Web.Extensions&amp;quot;&lt;/span&gt; assembly=&lt;span class="hl str"&gt;&amp;quot;Extensions&amp;quot;&lt;/span&gt;/&amp;gt; &lt;/pre&gt;
&lt;p&gt;
Note that the application will need references to the ASP.NET AJAX assembly and the
AJAX Control Toolkit as well. Add a &lt;code&gt;ScriptManager&lt;/code&gt; to the page, and extenders
for the &lt;code&gt;Button&lt;/code&gt;, &lt;code&gt;Image&lt;/code&gt; and &lt;code&gt;Panel&lt;/code&gt;.
&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span class="hl kwa"&gt;&amp;lt;kbr:HelpExtender&lt;/span&gt; ID=&lt;span class="hl str"&gt;&amp;quot;help1&amp;quot;&lt;/span&gt; runat=&lt;span class="hl str"&gt;&amp;quot;server&amp;quot;&lt;/span&gt; TargetControlID=&lt;span class="hl str"&gt;&amp;quot;Button1&amp;quot;&lt;/span&gt; HelpContextKey=&lt;span class="hl str"&gt;&amp;quot;1&amp;quot;&lt;/span&gt; HelpPanelID=&lt;span class="hl str"&gt;&amp;quot;HelpPanel&amp;quot;&lt;/span&gt; ServiceMethod=&lt;span class="hl str"&gt;&amp;quot;GetHelp&amp;quot;&lt;/span&gt; /&amp;gt; &lt;span class="hl kwa"&gt;&amp;lt;kbr:HelpExtender&lt;/span&gt; ID=&lt;span class="hl str"&gt;&amp;quot;help2&amp;quot;&lt;/span&gt; runat=&lt;span class="hl str"&gt;&amp;quot;server&amp;quot;&lt;/span&gt; TargetControlID=&lt;span class="hl str"&gt;&amp;quot;Image1&amp;quot;&lt;/span&gt; HelpContextKey=&lt;span class="hl str"&gt;&amp;quot;2&amp;quot;&lt;/span&gt; HelpPanelID=&lt;span class="hl str"&gt;&amp;quot;HelpPanel&amp;quot;&lt;/span&gt; ServiceMethod=&lt;span class="hl str"&gt;&amp;quot;GetHelp&amp;quot;&lt;/span&gt; /&amp;gt; &lt;span class="hl kwa"&gt;&amp;lt;kbr:HelpExtender&lt;/span&gt; ID=&lt;span class="hl str"&gt;&amp;quot;help3&amp;quot;&lt;/span&gt; runat=&lt;span class="hl str"&gt;&amp;quot;server&amp;quot;&lt;/span&gt; TargetControlID=&lt;span class="hl str"&gt;&amp;quot;Panel1&amp;quot;&lt;/span&gt; HelpContextKey=&lt;span class="hl str"&gt;&amp;quot;3&amp;quot;&lt;/span&gt; HelpPanelID=&lt;span class="hl str"&gt;&amp;quot;HelpPanel&amp;quot;&lt;/span&gt; ServiceMethod=&lt;span class="hl str"&gt;&amp;quot;GetHelp&amp;quot;&lt;/span&gt; /&amp;gt; &lt;/pre&gt;
&lt;p&gt;
All that remains is to define the Web service that provides our help. We'll inject
an AJAX-friendly service method right into this page. In a more practical application,
the &lt;code&gt;if/else if&lt;/code&gt; structure could be replaced with database access, file
IO, or any other data retrieval. All that is required is that the method is static,
takes the appropriate parameters, and returns the expected &lt;code&gt;string&lt;/code&gt; result.
&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span class="hl kwa"&gt;&amp;lt;script&lt;/span&gt; runat=&lt;span class="hl str"&gt;&amp;quot;Server&amp;quot;&lt;/span&gt; type=&lt;span class="hl str"&gt;&amp;quot;text/C#&amp;quot;&lt;/span&gt;&amp;gt; &lt;/pre&gt;
&lt;pre class="code"&gt;&lt;span class="hl sym"&gt;[&lt;/span&gt;System&lt;span class="hl sym"&gt;.&lt;/span&gt;Web&lt;span class="hl sym"&gt;.&lt;/span&gt;Services&lt;span class="hl sym"&gt;.&lt;/span&gt;WebMethod&lt;span class="hl sym"&gt;]&lt;/span&gt; &lt;span class="hl sym"&gt;[&lt;/span&gt;System&lt;span class="hl sym"&gt;.&lt;/span&gt;Web&lt;span class="hl sym"&gt;.&lt;/span&gt;Script&lt;span class="hl sym"&gt;.&lt;/span&gt;Services&lt;span class="hl sym"&gt;.&lt;/span&gt;ScriptMethod&lt;span class="hl sym"&gt;]&lt;/span&gt; &lt;span class="hl kwa"&gt;public
static&lt;/span&gt; &lt;span class="hl kwb"&gt;string&lt;/span&gt; &lt;span class="hl kwd"&gt;GetHelp&lt;/span&gt;&lt;span class="hl sym"&gt;(&lt;/span&gt;&lt;span class="hl kwb"&gt;string&lt;/span&gt; helpContextKey&lt;span class="hl sym"&gt;)&lt;/span&gt; &lt;span class="hl sym"&gt;{&lt;/span&gt; &lt;span class="hl kwa"&gt;if&lt;/span&gt; &lt;span class="hl sym"&gt;(&lt;/span&gt;helpContextKey &lt;span class="hl sym"&gt;==&lt;/span&gt; &lt;span class="hl str"&gt;&amp;quot;1&amp;quot;&lt;/span&gt;&lt;span class="hl sym"&gt;)&lt;/span&gt; &lt;span class="hl kwa"&gt;return&lt;/span&gt; &lt;span class="hl str"&gt;&amp;quot;There
is help awaiting you.&amp;quot;&lt;/span&gt;&lt;span class="hl sym"&gt;;&lt;/span&gt; &lt;span class="hl kwa"&gt;else
if&lt;/span&gt; &lt;span class="hl sym"&gt;(&lt;/span&gt;helpContextKey &lt;span class="hl sym"&gt;==&lt;/span&gt; &lt;span class="hl str"&gt;&amp;quot;2&amp;quot;&lt;/span&gt;&lt;span class="hl sym"&gt;)&lt;/span&gt; &lt;span class="hl kwa"&gt;return&lt;/span&gt; &lt;span class="hl str"&gt;&amp;quot;Excellent
clicking, friend!&amp;quot;&lt;/span&gt;&lt;span class="hl sym"&gt;;&lt;/span&gt; &lt;span class="hl kwa"&gt;else&lt;/span&gt; &lt;span class="hl kwa"&gt;return&lt;/span&gt; &lt;span class="hl str"&gt;&amp;quot;There
is no help found for the likes of you.&amp;quot;&lt;/span&gt;&lt;span class="hl sym"&gt;;&lt;/span&gt; &lt;span class="hl sym"&gt;}&lt;/span&gt; &lt;/pre&gt;
&lt;pre class="code"&gt;&lt;span class="hl kwa"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt; &lt;/pre&gt;
&lt;p&gt;
Running the page now shows that each control has a help cursor. When clicked, JavaScript
issues an asynchronous Web service call which populates a portion of the page with
context-sensitive help. The control extender is finished.
&lt;/p&gt;
&lt;img src="content/attachments/screen.jpg" alt="" /&gt; 
&lt;h4&gt;Conclusion
&lt;/h4&gt;
&lt;p&gt;
ASP.NET &lt;acronym title="Asynchronous JavaScript and XML"&gt;AJAX&lt;/acronym&gt; is an excellent
tool to provide a richer experience to the user by taking advantage of the control
extender model and asynchronous callbacks. With a little footwork, it is possible
to create extenders that add complex behaviors to a variety of server controls, potentially
saving considerable effort down the road. The AJAX Control Toolkit provides classes
that simplify the process of creating your own extenders. Also, because the AJAX Control
Toolkit is open source, you can download the existing control extenders and add behaviors
to them, as well.
&lt;/p&gt;
&lt;p&gt;
Happy Coding!
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.notesoncode.com/articles/aggbug.ashx?id=ad872df0-da73-44df-9c07-03b38e437995" /&gt;</description>
      <comments>http://www.notesoncode.com/articles/CommentView,guid,ad872df0-da73-44df-9c07-03b38e437995.aspx</comments>
      <category>ASP.NET</category>
      <category>AJAX</category>
    </item>
    <item>
      <trackback:ping>http://www.notesoncode.com/articles/Trackback.aspx?guid=15e0316e-e337-41a5-a2fe-522f15388bf8</trackback:ping>
      <pingback:server>http://www.notesoncode.com/articles/pingback.aspx</pingback:server>
      <pingback:target>http://www.notesoncode.com/articles/PermaLink,guid,15e0316e-e337-41a5-a2fe-522f15388bf8.aspx</pingback:target>
      <dc:creator>Administrator</dc:creator>
      <wfw:commentRss>http://www.notesoncode.com/articles/SyndicationService.asmx/GetEntryCommentsRss?guid=15e0316e-e337-41a5-a2fe-522f15388bf8</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
A few months ago I contributed to an open-source project for the first time. This
was an exciting moment for me. Until recently, I had always borrowed knowledge from
blogging gurus such as <a href="http://weblogs.asp.net/scottgu/default.aspx" rel="nofollow">Scott
Guthrie</a> and <a href="http://www.hanselman.com/blog/" rel="nofollow">Scott Hanselman</a>,
and open source repositories such as <a href="http://www.codeproject.com/" rel="nofollow">Code
Project</a> and <a href="http://web.sourceforge.com/" rel="nofollow">SourceForge</a>.
This world of programming was, and still is, a great well of programming tips and
tricks that help me out quite regularly.
</p>
        <p>
As I developed the framework for Notes on Code, I started using the <acronym title="cascading style sheets">CSS</acronym> Friendly
Control Adapters, an open source library available on <a href="http://www.codeplex.com/cssfriendly" rel="nofollow">CodePlex.com</a>.
These control adapters improve the quality of ASP.NET page markup by reducing the
frequency of <code>&lt;table&gt;</code> objects on the page when rendering complex
controls such as the <code>TreeView</code>.
</p>
        <p>
On my pages, I kept a small link to <acronym title="World Wide Web Consortium">W3C</acronym> to
verify that my <acronym title="Extended Hypertext Markup Language">XHTML</acronym> was
correct. What to my surprise when I found that it was not. The culprit turned out
to be the control adapters, which injected a <code>&lt;link&gt;</code> tag in the <code>&lt;body&gt;</code> section.
After searching Google for some time, it became clear to me that this was an unidentified
bug.
</p>
        <p>
It was a simple fix, really. It only took a moment to find the offending lines in
the source code and, due to the quality design of the original product, find a suitable
alternative.
</p>
        <p>
I was very impressed with the management of the project by <a href="http://www.sidesofmarch.com/" rel="nofollow">bdemarzo</a>.
By the evening of the same day, the source code for the project was updated to include
the changes.
</p>
        <p>
I'll say that it felt like a rite of passage for me. I felt like I had something to
contribute to the community, however small that contribution might be. If you haven't
tried it yet, go for it. Go anywhere there is code and try it out.
</p>
        <p>
Happy Coding!
</p>
        <img width="0" height="0" src="http://www.notesoncode.com/articles/aggbug.ashx?id=15e0316e-e337-41a5-a2fe-522f15388bf8" />
      </body>
      <title>Contributing to Open Source</title>
      <guid isPermaLink="false">http://www.notesoncode.com/articles/PermaLink,guid,15e0316e-e337-41a5-a2fe-522f15388bf8.aspx</guid>
      <link>http://www.notesoncode.com/articles/2007/06/14/ContributingToOpenSource.aspx</link>
      <pubDate>Thu, 14 Jun 2007 03:12:31 GMT</pubDate>
      <description>&lt;p&gt;
A few months ago I contributed to an open-source project for the first time. This
was an exciting moment for me. Until recently, I had always borrowed knowledge from
blogging gurus such as &lt;a href="http://weblogs.asp.net/scottgu/default.aspx" rel="nofollow"&gt;Scott
Guthrie&lt;/a&gt; and &lt;a href="http://www.hanselman.com/blog/" rel="nofollow"&gt;Scott Hanselman&lt;/a&gt;,
and open source repositories such as &lt;a href="http://www.codeproject.com/" rel="nofollow"&gt;Code
Project&lt;/a&gt; and &lt;a href="http://web.sourceforge.com/" rel="nofollow"&gt;SourceForge&lt;/a&gt;.
This world of programming was, and still is, a great well of programming tips and
tricks that help me out quite regularly.
&lt;/p&gt;
&lt;p&gt;
As I developed the framework for Notes on Code, I started using the &lt;acronym title="cascading style sheets"&gt;CSS&lt;/acronym&gt; Friendly
Control Adapters, an open source library available on &lt;a href="http://www.codeplex.com/cssfriendly" rel="nofollow"&gt;CodePlex.com&lt;/a&gt;.
These control adapters improve the quality of ASP.NET page markup by reducing the
frequency of &lt;code&gt;&amp;lt;table&amp;gt;&lt;/code&gt; objects on the page when rendering complex
controls such as the &lt;code&gt;TreeView&lt;/code&gt;.
&lt;/p&gt;
&lt;p&gt;
On my pages, I kept a small link to &lt;acronym title="World Wide Web Consortium"&gt;W3C&lt;/acronym&gt; to
verify that my &lt;acronym title="Extended Hypertext Markup Language"&gt;XHTML&lt;/acronym&gt; was
correct. What to my surprise when I found that it was not. The culprit turned out
to be the control adapters, which injected a &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; tag in the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; section.
After searching Google for some time, it became clear to me that this was an unidentified
bug.
&lt;/p&gt;
&lt;p&gt;
It was a simple fix, really. It only took a moment to find the offending lines in
the source code and, due to the quality design of the original product, find a suitable
alternative.
&lt;/p&gt;
&lt;p&gt;
I was very impressed with the management of the project by &lt;a href="http://www.sidesofmarch.com/" rel="nofollow"&gt;bdemarzo&lt;/a&gt;.
By the evening of the same day, the source code for the project was updated to include
the changes.
&lt;/p&gt;
&lt;p&gt;
I'll say that it felt like a rite of passage for me. I felt like I had something to
contribute to the community, however small that contribution might be. If you haven't
tried it yet, go f