Friday, August 15, 2008

Section 8.5.2 of CSS 2.1 and the border-color property

I realize this is minutea, but I wanted to get this down for later recall.

First of all, when working with Firefox, I usually find that it is reliably strict, and so developing for FF will allow you to get a result that transfers to other browsers. Of course, sometimes the strictness is annoying but at least it's reliable. In this case I thought I had found something it just wasn't doing right, but giving it the benefit of the doubt on just being a PITA, I looked at the spec and of course FF was proved right.

The problem was that I was setting some border colors for various containers on the page like so (heavily simplified):

.boxtype1
{
border-color:blue;
...other properties...
}
.boxtype1-alert
{
border-color:red;
...other properties...
}

What I was seeing was that boxtype1 was getting a black border color (the color of the 'color' property in the body tag), and the -alert type box was getting the proper red border - only in FF; IE (6 & 7) and Safari were 'fine' in that they displayed my chosen color as the border color. After cursing FF for it's lame implementation I decided to check the spec and found the answer as related to the use of some border-side specific styling and the order of styles implemented.

The fact is that other declarations subsequent to the style I was using to set color were setting other properties on left/right/top/bottom borders without setting the color:

.boxtype1
{
border-left:solid 2px;
}


This doesn't leave the color as previously set, but makes it work as "inherit" or default because it was not set specifically.

The solution is to either make sure the order of execution is correct (a fragile waste of time) or set each border specifically, making sure it will take on the style no matter the order.

You can see for yourself that if you have the following html:

<div class="boxtype1">
<p>
Some text with a border around container.
</p>
</div>

and apply the following styles:


body
{
color:Blue;
}
.boxtype1
{
border:solid 1px;
}
.boxtype1
{
border-color:Red;
}
.boxtype1
{
border-left:solid 2px;
}

You will get a red border all the way around in IE, but will have a blue, 2px border on the left in FF.
Submit this story to DotNetKicks

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