Bootstrap Radio Buttons with ASP.NET Web Forms and UpdatePanels

(Update 2015/07/07: Debugged and cleaned up code snippets and attached sample Visual Studio project.)

Let’s say I am taking a WebForms site and updating it to make it look nicer. Ideally I would update the project to ASP.NET MVC, but let’s say that won’t be possible.

As part of my site, I have tags allowing partial postbacks through AJAX, and I have controls doing automatic postback when the value is changed.

<asp:RadioButton runat="server" id="radioA1" GroupName="radioA" AutoPostBack="True"/> 
<label for="radioA1">Option 1</label> 
<br/>
<asp:RadioButton runat="server" id="radioA2" GroupName="radioA" AutoPostBack="True"/> 
<label for="radioA2">Option 2</label>

Two radio buttons with default styling

Now, to make those radio buttons look nicer, I wrap them up like so, using Bootstrap’s CSS rules:

<div class="btn-group" data-toggle="buttons">
    <label class="btn btn-default">
     <asp:RadioButton runat="server" id="radioB1" GroupName="radioB" AutoPostBack="True"/>
     Option 1 
    </label>
    <label class="btn btn-default">
     <asp:RadioButton runat="server" id="radioB2" GroupName="radioB" AutoPostBack="True"/>
     Option 2
    </label>
</div>

Two radio buttons styled as buttonsImmediately, there is a problem. Although the radio buttons will switch the active state as intended, they do not post back. Due to the AutoPostBack=”True” attribute, ASP.NET generates a click event on each radio button, which goes out via AJAX and results in a partial postback. However, the label wrapping around the radio button is preventing the click event from being fired.

I played around with changes to the code and finally landed on a solution. First, I added runat=”server” and an id to each of the labels, because they will be modified in the codebehind page.

<div class="btn-group" data-toggle="buttons">
    <label runat="server" id="lbl_radioC1" class="btn btn-default">
     <asp:RadioButton runat="server" id="radioC1" GroupName="radioC" AutoPostBack="True"/>
     Option 1 
    </label>
    <label runat="server" id="lbl_radioC2" class="btn btn-default">
     <asp:RadioButton runat="server" id="radioC2" GroupName="radioC" AutoPostBack="True"/>
     Option 2
    </label>
</div>

Now, in the codebehind, I created a list of all the pairs of label and radio button that need to trigger postbacks:

protected void Page_Load(object sender, EventArgs e)
{
    List<Tuple<RadioButton, HtmlGenericControl>> listRadio = new List<Tuple<RadioButton, HtmlGenericControl>>();
    listRadio.Add(new Tuple<RadioButton, HtmlGenericControl>(radioC1, lbl_radioC1));
    listRadio.Add(new Tuple<RadioButton, HtmlGenericControl>(radioC2, lbl_radioC2));
}

Finally, for each pair, I did the following steps:

  1. Assign the same onclick action on the label that is assigned to the radio button. This way, clicking the label will trigger the same postback that was previously triggered by clicking the radio button.
  2. Make sure the active class is assigned to the selected radio button option.

The code I used looked like this:

foreach (Tuple<RadioButton, HtmlGenericControl> objPair in listRadio)
{
    objPair.Item2.Attributes["class"] = "btn btn-default " + (objPair.Item1.Checked ? " active" : "");
    objPair.Item2.Attributes["onclick"] = "javascript:setTimeout('__doPostBack(\\'" + objPair.Item1.ClientID + "\\',\\'\\')', 0);";
}

Finally, the styled radio buttons were posting back, and in testing worked in all browsers I had available. There may be more elegant ways to solve this problem, but this one worked for me. After multiple failed attempts at solving the problem, I’m happy with an inelegant solution if it works.

Download a sample Visual Studio 2010 C# WebForms project here: BootstrapDataToggleTest. (Click Download zip to get the entire project.)