Suppose you want to extend a DataList and have it put out a div for each row. The RepeatLayout property can be either Flow (“Items are displayed without a table structure”) or
Table (“Items are displayed in a table”). Since we want divs, we’re after RepeatLayout = RepeatLayout.Flow. Not so fast, though. This control isn’t that easy to extend.
What you get is a <span> which wraps the rest of the markup. More so, <div> rows are separated with superfluous <br>s that come out of nowhere!
<span id="foo">
<div class="bar"></div>
<br>
<div class="bar"></div>
<br>
<div class="bar"></div>
<br>
</span>
The first impulse is to override the TagKey property:
protected override HtmlTextWriterTag TagKey
{
get { return HtmlTextWriterTag.Div; }
}
Just about every control will yield and render what you tell it, but not DataList. Beat your head against the wall—you still get a <span>. How weird is it to have an inline element wrap a block element!
My next guess was to look inside the ASP.NET CSS Friendly Control Adapters, but I was in for a disappointment. The
DataListAdapter does not accommodate the “flow” layout. It merely produces a cleaner <table>. Back to the drawing board.
Eventually, I wrote my own, simple adapter:
namespace MyNamespace
{
public class MyListControlAdapter : WebControlAdapter
{
protected override void RenderContents (HtmlTextWriter w)
{
DataList dataList = Control as DataList;
if (dataList != null)
{
foreach (DataListItem li in dataList.Items)
li.RenderControl (w);
}
else
{
base.RenderContents (w);
}
}
}
}
which produced pristine markup:
<div id="foo">
<div class="bar"></div>
<div class="bar"></div>
<div class="bar"></div>
</div>
Remember to create, or edit, a file named default.browser in the App_Browsers folder and add the following section:
<browsers>
<browser refID="Default">
<controlAdapters>
<adapter
controlType="MyNamespace.MyListControl"
adapterType="MyNamespace.MyListControlAdapter" />
</controlAdapters>
</browser>
</browsers>
Hope this tip saves someone a day or two of head beating.