Monday, August 11, 2008

Asp.Net AJAX Client Side Templated Data Bound Control

Source Code Available from Hydrus Software

I recently read these two articles by Dino Esposito about ajax templates (part1, part2) and was intrigued by the possibilities. I spend a lot of time working on customizing Community Server which is one page after another of templated data-bound lists. In a number of situations we have needed to customize lists to respond to client input. This can present performance problems when lists are in tabs, or the page is very heavy.


In any case, I had some time available and worked out a client script control that implements the template builder Mr. Esposito showed in part 1 of his article.


I created a server control that allows you to specify header, item, and footer templates for a basic data list that will be bound on the client based on either a given web service method, or on a data-source provided client side. The templates are rendered server-side before being passed to the client behavior which allows you to use other server-side controls in the development of the templates.


I had not built an asp.net ajax client script control before, but the magic lies in the IScriptControl interface. There are plenty of articles out there on this, so I won't go into it. At a high level, this interface provides a way for you to instantiate your client-side object (behavior) with properties set on your server side control.


Finally, in order to make the server-side declarative coding a bit cleaner, I implemented the client-template replacement string as a control. Once you have this nifty server-side control, you can setup the client repeater with code like this:




<HydrusClient:ClientRepeater runat="server" ID="CustomerList" ServiceMethod="GetCustomers"
ServicePath="Service.svc" DataBindingFunctionName="MyFunction">
<HeaderTemplate>
<table>
<thead>
<tr>
<td>
<asp:Label runat="server">Full Name</asp:Label>
</td>
<td>
<asp:Label runat="server">Role</asp:Label>
</td>
</tr>
</thead>
<tbody>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td>
<HydrusClient:ClientBoundDataProperty runat="server" PropertyName="FullName" />
</td>
<td>
<HydrusClient:ClientBoundDataProperty runat="server" PropertyName="Role" />
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</tbody>
</table>
</FooterTemplate>
</HydrusClient:ClientRepeater>

A few words about getting the control to work properly...



  1. While we instantiate the templates into containers in CreateChildControls, the templates are rendered into strings in the RenderChildControls method. These strings must have insignificant whitespace removed.

  2. Because the template strings must be properties on the client-side behavior, we cannot call RegisterScriptDescriptors until after the children have been rendered, thus we make the call in the overridden Render method.

  3. The ScriptManager must have the id of a rendered client element with which to register the behavior when creating the ScriptControlDescriptor. In this case my server control renders a placeholder. You could write this control as a rendered control extension and force the user to identify the rendered element.
Submit this story to DotNetKicks

No comments: