This tutorial shows an implementation which allows multiple fields to be bound to the item labels. We needed this in order to enrich the display of radio button lists in one of our applications. We’re going to look in detail at the code for the existing ASP.Net controls, which you can browse by disassembling the System.Web assembly in Reflector. The kind of solution presented here should also work equally well for CheckBoxList and DropDownList, because all three controls inherit most of their data binding functionality from the ListControl base class. |
|
GridView Hyperlink Field
|
Anyone who has used GridView in any detail will know that you can create a type of databound column in the GridView which renders out a Hyperlink. The underlying data which is used to generate the text and URL of the hyperlink, and the format String to produce the actual output, are specified in properties declared in the markup.
Because often multiple fields are required to generate the Url (e.g. if the Url has multiple query string parameters), the DataNavigateUrlFields property accepts a comma delimited list of fields to bind. To display multiple items, the format string simply refers to each item required: |
<asp:GridView ID="gvMaster" runat="server" AutoGenerateColumns="False">
<Columns>
<asp:HyperLinkField DataNavigateUrlFields="CategoryID,Processed" Text="Link To MyPage" DataNavigateUrlFormatString="~/MyPage.aspx?Category={0}&ShowProcessed={1}" />
</Columns>
</asp:GridView> |
Inspecting this class in Reflector show that this is automatically converted and stored as a string array: |
|
[TypeConverter(typeof(StringArrayConverter))]
[DefaultValue((string)null)]
public virtual string[] DataTextFields {get; set;} |
During data binding, the object properties corresponding to each field are investigated to yield reflection objects: |
|
|
|
// Caches the reflection data for databinding
private PropertyDescriptor[] urlFieldDescs;
private void OnDataBindField(object sender, EventArgs e)
{
if (this.urlFieldDescs == null)
PropertyDescriptorCollection p=TypeDescriptor.GetProperties(component);
string[] dataNavigateUrlFields = this.DataNavigateUrlFields;
int num = dataNavigateUrlFields.Length;
this.urlFieldDescs = new PropertyDescriptor[num];
for (int i = 0; i < num; i++)
{
dataTextField = dataNavigateUrlFields[i];
if (dataTextField.Length != 0)
{
this.urlFieldDescs[i] = properties.Find(dataTextField, true);
if ((this.urlFieldDescs[i] == null) && !base.DesignMode)
{
throw new HttpException(SR.GetString("Field_Not_Found",
new object[]
{
dataTextField}));
}
}
}
}
...
}
|
From these property definitions, reflection is used to get an array of values for the current object: |
|
|
|
// get an array of values from the current dataItem’s properties
int length = this.urlFieldDescs.Length;
object[] dataUrlValues = new object[length];
for (int j = 0; j < length; j++)
{
if (this.urlFieldDescs[j] != null)
{
dataUrlValues[j] = this.urlFieldDescs[j].GetValue(component);
}
}
HyperLink link = (HyperLink)sender;
string s = this.FormatDataNavigateUrlValue(dataUrlValues);
link.NavigateUrl = s;
|