GridView is one of the significant controls in ASP.NET 2.0 and later versions. No doubt it reduces a lot of work time. However, customizing the
GridView control is not an easy task. For example, it's hard to add a radio button column to the
GridView. This article demonstrates the reason why a radio button column cannot act as normal and how to create a simple and extensible radio button
What's the Problem
Typically, we are able to add a custom column by implementing an
ITemplate interface if the
GridView's columns are not auto generated or we can add the custom column in the
OnRowDataBound method if the columns are auto generated. For example, we could add a radio column using the following code:
protected override void OnRowDataBound(GridViewRowEventArgs e)
TableCell tc = new TableCell();
if (e.Row.RowType == DataControlRowType.DataRow)
RadioButton radioButton = new RadioButton()
ID = "NormalRadioButton",
GroupName = "NormalRadioButtonGroupName",
AutoPostBack = true
This code added a radio button cell to each row of the
GridView. Also we specified the same
GroupName for each radio button. Note that the same ID is allowed here. I'll explain it later.
By now, everything is OK. However, if we compile this code and open the *.aspx file in the browser, we'll find the behavior of the radio column is not correct:
Why can we select two radio buttons at the same time? Haven't we added all the radio buttons into a group named "
NormalRadioButtonGroupName"? The culprit is a particular control called
NamingContainer is a particular parent control which implements the
INamingContainer interface. It is used to "contain" the child control. It is also used to generate the
UniqueID of the control. For example, a
TextBox is added to a
Panel, assume the
Panel is the
NamingContainer of the
TextBox, the Panel's ID is "
Panel1" and the TextBox's ID is "
textBox1", then the TextBox's
UniqueID should be "
Panel1$textBox1". By the way, the
ClientID of a control is the same as the
UniqueID except the split character - use '_' to replace '$'. Let's go back to section "What's the problem". When I created the radio button for each row of the
GridView, I specified the same ID of the radio button. The
NamingContainer guarantees the IDs of the radio buttons won't be duplicated. In particularly, the IDs of the example are as the following code:
NormalRadioButtonGridView1" is the ID of the
ctlXX" is the ID of the row (Because we didn't assign a value to each row, ASP.NET automatically generated the control ID as "
NormalRadioButton" is the radio button ID we assigned. More details about
NamingContainer can be found here.
Find and Resolve the Problem
Now we view the source code of the page in the browser. It is as below:
Note the "
name" attribute of each radio button. Although we assigned the same group name for each radio button, due to the
NamingContainer, the truely "
name" value is combined by the ID of
NamingContainer of each level. This is why the system does not think the radios are in one group so that we can select more than one radio buttons at the same time.
To solve this problem, a first idea is to modify the "
name" value. Unfortunately, the "
name" value contains the hierarchy of the radio button, if we modify it, the radio button will lose its infomation after post back. But if you don't want to process the logic in the server side, in other words, you turn off the
AutoPostBack property, then modify the "
name" attribute of each radio button and assign the same value to it is a good solution. In most situations, we should let the
GridView post back to invoke our own event functions such as "selected index changed". So we should find a way to correct the behavior even if it will post back to the server.
First and most important, we should simulate a "Group" mechanism. Look at the "
__doPostBack. This function is auto generated by ASP.NET if there is a control who will post back data to the server. It takes two arguments, the first argument specifies which control posts back data; the second argument is a value to pass to the server. We can use this function to pass a value such as
fromGridViewRadioButton to the server. In the server side, if we capture a posted data whose sender's ID is the current radio button control and the passed value is
fromGridViewRadioButton, we set the radio button's status
Checked; if the sender's ID is not the current radio button control and the passed value is
fromGridViewRadioButton, we set the radio button's status
UnChecked. We should write code as below:
protected override bool LoadPostData(string postDataKey,
Boolean flag = base.LoadPostData(postDataKey, postCollection);
if (postCollection[EVENT_TARGET] != this.UniqueID)
if (postCollection[EVENT_ARGUMENT] == RADIO_BUTTON_FLAG)
if (this.Checked != false)
this.Checked = false;
flag = true;
Second, we should capture the output HTML text and add
fromGridViewRadioButton argument to the
protected override void Render(HtmlTextWriter writer)
StringBuilder sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);
HtmlTextWriter customHtmlWriter = new HtmlTextWriter(sw);
String pageResult = ProcessPageOutput(sb.ToString());
virtual protected String ProcessPageOutput(String outputString)
Finally, when the selected radio button changes, we should notify the
GridView to change the selected index:
protected override void OnCheckedChanged(EventArgs e)
Using the Code
Build the source code and drag the DLL to the toolbox of Visual Studio. Use the
RadioButtonGridView as you use the normal
Note that here is another control named
RadioButtonEx in the DLL. This radio button can be used not only in the
GridView. Whenever you want to add a group of radio buttons in a container, but find the unexpected behavior as the
GridView, try to use
You can override
ProcessPageOutput to add your own logic to make this control meet your request.
- 2009-04-23 Original version