I am generating a radio button list programatically in C#.NET 3.5 and using a RadioButtonList
in order to do so. However, something I find very frustrating is the RepeatLayout
property, which can only be set to Flow
or Table
.
Tables are for tabular data, not for displaying forms. And flow isn't helpful because it doesn't lend itself well to styling.
What I really want is a nest of divs I can address with CSS. Can this be done?
Some examples to illustrate what I'm talking about and example code below.
Example of flow
<span id="s1">
<input id="s1_0" type="radio" value="Answer A" name="s1">
<label for="s1_0">Answer A</label>
<br>
<input id="s1_1" type="radio" value="Answer B" name="s1">
<label for="s1_1">Answer B</label>
</span>
Example of table
<table border="0" id="s1">
<tbody>
<tr>
<td><input type="radio" value="Answer A" name="s1" id="s1_0"><label for="s1_0">Answer A</label></td>
</tr>
<tr>
<td><input type="radio" value="Answer B" name="s1" id="s1_1"><label for="s1_1">Answer B</label></td>
</tr>
</tbody>
</table>
What I actually want
<div id="s1">
<div>
<input type="radio" value="Answer A" name="s1" id="s1_0">
<label for="s1_0">Answer A</label>
</div>
<div>
<input type="radio" value="Answer B" name="s1" id="s1_1">
<label for="s1_1">Answer B</label>
</div>
</div>
C# Code I'm using to generate the list
I know whatever the solution is, won't be as quick and easy as this, but I'm putting it here so you can get an idea of the context in which I'm using it.
RadioButtonList rbl = new RadioButtonList { RepeatLayout = RepeatLayout.Table };
foreach (ControlValue cv in MasterControl.listControlValues)
{
rbl.Items.Add(new ListItem(cv.name, cv.value));
}
ControlContainer.Controls.Add(rbl);
You may want to use WebControlAdapter to change the way of how RadioButtonList
is rendered.
Below is the complete code for your case:
public class RadioButtonListAdapter : WebControlAdapter
{
protected override void RenderBeginTag(HtmlTextWriter writer)
{
writer.RenderBeginTag("div");
}
protected override void RenderEndTag(HtmlTextWriter writer)
{
writer.RenderEndTag();
}
protected override void RenderContents(HtmlTextWriter writer)
{
var adaptedControl = (RadioButtonList) Control;
int itemCounter = 0;
writer.Indent++;
foreach (ListItem item in adaptedControl.Items)
{
var inputId = adaptedControl.ClientID + "_" + itemCounter++;
// item div
writer.RenderBeginTag("div");
writer.Indent++;
// input
writer.AddAttribute("type", "radio");
writer.AddAttribute("value", item.Value);
writer.AddAttribute("name", adaptedControl.ClientID);
writer.AddAttribute("id", inputId);
if (item.Selected)
{
writer.AddAttribute("checked", "checked");
}
writer.RenderBeginTag("input");
writer.RenderEndTag();
// label
writer.AddAttribute("for", inputId);
writer.RenderBeginTag("label");
writer.Write(item.Value);
writer.RenderEndTag();
// div
writer.Indent--;
writer.RenderEndTag();
}
writer.Indent--;
}
}
To connect this adapter to you application you have two options. First is to do it programmatically in page constructor:
var adapters = Context.Request.Browser.Adapters;
var radioButtonListType = typeof(RadioButtonList).AssemblyQualifiedName;
var adapterType = typeof(RadioButtonListAdapter).AssemblyQualifiedName;
if (!adapters.Contains(radioButtonListType))
{
adapters.Add(radioButtonListType, adapterType);
}
Second option is using .browser
file:
Add new Browser File
to your project. It will reside in App_Browsers
folder. Then replace contents with following declaration:
<browsers>
<browser refID="Default">
<controlAdapters>
<adapter controlType="System.Web.UI.WebControls.RadioButtonList"
adapterType="<your namespace>.RadioButtonListAdapter" />
</controlAdapters>
</browser>
</browsers>
As a reference you can use links from ScottGu's post ASP.NET 2.0 Control Adapter Architecture they can give a good basement in this topic.
Also there is an open source CSS Friendly Control Adapters project that adresses some of rendering issues of default ASP.NET controls.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With