Click here to Skip to main content
15,885,546 members
Articles / Web Development / ASP.NET
Article

Rich List Controls in ASP.NET

Rate me:
Please Sign up or sign in to vote.
4.71/5 (21 votes)
1 Nov 20054 min read 161.2K   2.7K   67   25
Improvements to the standard ASP.NET list controls including styles for individual list items and an improved API.

Image 1

Introduction

This article chronicles my quest to both improve upon the existing ASP.NET list controls but also to learn about some of the hidden mysteries of Custom Web Controls.

Background

Custom Web Controls have been one of my favorite features of the ASP.NET framework from the time I first started using it three years ago. I had been doing web development for many years before that and the idea of being able to encapsulate my logic into controls was very appealing. The largest problem I kept running into when developing my own controls was the poor documentation on some of the advanced features. I looked at the simple controls I was developing, then I looked at rich controls such as the DataGrid, and I noticed a large disparity. I found many articles on custom web controls and even read this book. Although these resources were helpful, they did not reveal the hidden secrets of the Microsoft web controls.

This article explains some of the things I learned while developing my own version of the ASP.NET list controls. I found the individual list items (RadioButton and CheckBox) to be very rich but when placed inside of their respective list controls (RadioButtonList and CheckBoxList) they list a lot of functionality. I wanted to be able to customize the styles for the individual list items and to have tooltips as well. I did, however, really like some of the features that the list controls afforded me such as data binding and layout control. When I discovered Lutz Roeder's Reflector, I decided to pick apart the Microsoft controls in an effort to write my own.

Notable Findings

Some of the code used in the ASP.NET list controls is marked as internal so us lowly non-Microsoft developers do not have access to them. To do this, I simply copied their code and made it public. There were some parts which were public but I had never seen documented. One such class is the interface System.Web.UI.WebControls.IRepeatInfoUser. This class facilitates the layout control for any repeating list of items. The most notable part of the interface is:

C#
public void RenderItem(ListItemType itemType, int repeatIndex, 
  RepeatInfo repeatInfo, HtmlTextWriter writer);
This code is called for each item in the list so that you can render each item yourself. Here is the complete code for implementing this method in my RadioList Control:
C#
public void RenderItem(ListItemType itemType, int repeatIndex, 
  RepeatInfo repeatInfo, HtmlTextWriter writer)
{
  RadioButton button1 = new RadioButton();
  button1.Page = Page;
  button1.GroupName = UniqueID;
  button1.ID = string.Concat(ClientID, "_", 
    repeatIndex.ToString(NumberFormatInfo.InvariantInfo));
  button1.Text = Items[repeatIndex].Text;
  button1.ToolTip = Items[repeatIndex].ToolTip;
  button1.Attributes["value"] = Items[repeatIndex].Value;
  button1.Checked = Items[repeatIndex].Selected;
  button1.TextAlign = TextAlign;
  button1.AutoPostBack = AutoPostBack;
  button1.TabIndex = radioButtonTabIndex;
  button1.Enabled = Enabled;

  foreach(string key in Items[repeatIndex].Attributes.Keys)
  {
    button1.Attributes[key] = Items[repeatIndex].Attributes[key];
  }

  button1.RenderControl(writer);
}
This code basically just using the information from the Items collection to build a RadioButton control and then to render it. It is that simple!

RichListItems

Most of the changes that I made were to the System.Web.UI.WebControls.ListItem class. I made my own version called RichListItem. I added a property of type System.Web.UI.WebControls.TableItemStyle called Style. This allows for each list item to have its own style settings. The attributes on this property are important when it comes to the behavior of this class being persisted when using the controls in design mode.

C#
[
  Category("Behavior"),
  Description("The Style of this item"),
  DesignerSerializationVisibility(DesignerSerializationVisibility.Content),       
  NotifyParentProperty(true),
  PersistenceMode(PersistenceMode.Attribute)
]
By using PersistenceMode.Attribute, the style information for each list item is persisted as attributes (using the '-' naming convention). The DesignerSerializationVisibility.Content is what tells Visual Studio to persist the styles as content.

Besides adding styles to the list items, I added the ToolTip property. In order to do this, I had to change the ViewState persistence to save the ToolTip along with the Text and the Value of the list item.

C#
internal object SaveViewState()
{
  if(misc.Get(TEXTISDIRTY) && misc.Get(VALUEISDIRTY) && misc.Get(TOOLTIPISDIRTY))
  {
    return new Triplet(Text, Value, ToolTip);
  }
  else if (misc.Get(TEXTISDIRTY) && misc.Get(VALUEISDIRTY))
  {
    return new Pair(Text, Value);
  }
  else if (misc.Get(TEXTISDIRTY))
  {
    return Text;
  }
  else if (misc.Get(VALUEISDIRTY))
  {
    return new Pair(null, Value);
  }
  else if(misc.Get(TOOLTIPISDIRTY))
  {
    return new Pair(ToolTip, null);
  }
  return null;
}

internal void LoadViewState(object state)
{
  Pair pair;
  Triplet triplet;
  if (state == null)
  {
    return;
  }
  if ((state as Triplet) != null)
  {
    triplet = ((Triplet) state);
    Text = (string)triplet.First;
    Value = (string)triplet.Second;
    ToolTip = (string)triplet.Third;
  }
  else if ((state as Pair) != null)
  {
    pair = ((Pair) state);
    if (pair.First != null)
    {
      if(pair.Second != null)
        Text = (string)pair.First;
      else
        ToolTip = (string) pair.First;
    }
    if(pair.Second != null)
    {
      Value = ((string) pair.Second);
    }
    return;
  }
  this.Text = ((string)state);
}
An in depth explanation of state management is beyond the scope of this article but note how the LoadViewState and the SaveViewState methods compliment each other. In the case of the RichListItem, there are three possible values to be persisted: Text, Value, and ToolTip.

API Changes

There are some breaking changes as far as making the RichListControls backwards compatible with the ASP.NET list controls. There is still a base class, RichListControl, which provides the basis for all list controls. I have added another level of inheritance in between the list controls and the base RichListControl class. I broke them out into two different types: SingleSelectListControl and MutipleSelectListControl. This allows list controls which allow only one item to be selected to have properties for SelectedIndex, SelectedItem, SelectedValue, and SelectedText. List controls which allow multiple items to be selected have properties for SelectedIndices, SelectedItems, SelectedValues, and SelectedTexts. I have added a property to the base RichListControl called HasSelection which indicates whether or not any items are selected in the list. Here is an example of a possible use of these properties:

C#
if(list.HasSelection)
{
  foreach(RichListItem item in list.SelectedItems)
  {
    lblSelection.Text += String.Format(" {0}", item.Text);
  }
}
else
{
  lblSelection.Text = "No Selection";
}

Using the code

The RichListControls are used in the exact same way as the traditional ASP.NET list controls. Note the Style and ToolTip attributes below.

HTML
<%@ Register TagPrefix="List" Assembly="RichListControls" 
  Namespace="RichListControls" %>
<List:RichRadioButtonList id="list" runat="server">
  <Items>
    <list:RichListItem ToolTip="This is not that many miles" 
        Style-Font-Italic="True" Style-ForeColor="Green"
      Value="0">0 - 15</list:RichListItem>
    <list:RichListItem ToolTip="Most People Drive at least this much" 
          Value="5">15 - 30</list:RichListItem>
    <list:RichListItem Style-Font-Bold="True" Style-ForeColor="Firebrick" 
         Style-BackColor="LightYellow"
      Value="10">30+</list:RichListItem>
  </Items>
</List:RichRadioButtonList>

Points of Interest

There are a couple of helper classes I used which are worth noting. First, there is StyleHelper which is used by the RichDropDownList to convert a System.Web.UI.WebControls.Style to a string that can be used in an HTML style attribute. Most of this code is taken straight from internal methods in the System.Web dll.

There is also DataSourceHelper which is used in databinding. All of the code in this is taken from the System.Web dll.

History

  • 9/9/2004 - Initial release.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
Luke Foust is a software developer from San Diego, CA.

Comments and Discussions

 
QuestionDatabinding Question Pin
rbscene20-Sep-07 8:48
rbscene20-Sep-07 8:48 
Generalddl OnSelectedIndexChanged not firing. Pin
rymos15-Aug-07 9:20
rymos15-Aug-07 9:20 
QuestionWith RichCheckBoxList how do I select/check at server side Pin
nitadx2-Jan-07 0:52
nitadx2-Jan-07 0:52 
GeneralXML DataBinding [modified] Pin
michel petrovic19-Sep-06 21:54
michel petrovic19-Sep-06 21:54 
GeneralSelected Index Changed not called Pin
Dan Pupek15-May-06 5:31
Dan Pupek15-May-06 5:31 
GeneralRe: Selected Index Changed not called Pin
Mohamed Elzahaby29-May-06 14:18
Mohamed Elzahaby29-May-06 14:18 
GeneralDatabinding Pin
Mike DiRenzo4-Apr-06 10:44
Mike DiRenzo4-Apr-06 10:44 
GeneralNo PostBack!!! Pin
gooseman9-Jan-06 9:04
gooseman9-Jan-06 9:04 
QuestionDesigner Help Need ? Pin
returnofjedi20-Dec-05 22:42
returnofjedi20-Dec-05 22:42 
GeneralValidation Pin
jaredutley1-Nov-05 6:07
jaredutley1-Nov-05 6:07 
GeneralRe: Validation Pin
Luke Foust1-Nov-05 6:13
Luke Foust1-Nov-05 6:13 
GeneralConvert to VB.NET Pin
Kirk Quinbar10-Oct-05 8:28
Kirk Quinbar10-Oct-05 8:28 
GeneralStyle Attributes Pin
Dejan Petrovic9-Aug-05 16:07
Dejan Petrovic9-Aug-05 16:07 
GeneralRe: Style Attributes Pin
Luke Foust10-Aug-05 6:41
Luke Foust10-Aug-05 6:41 
GeneralRe: Style Attributes Pin
Dejan Petrovic10-Aug-05 18:24
Dejan Petrovic10-Aug-05 18:24 
GeneralView State Error Pin
michael80548-Jun-05 13:29
michael80548-Jun-05 13:29 
GeneralRe: View State Error Pin
beinhoff16-Mar-06 23:32
beinhoff16-Mar-06 23:32 
GeneralRe: Tooltip Pin
Luke Foust19-Nov-04 7:33
Luke Foust19-Nov-04 7:33 
GeneralRe: Tooltip Pin
Thea Burger21-Nov-04 22:54
Thea Burger21-Nov-04 22:54 
GeneralRe: Tooltip Pin
Thea Burger21-Nov-04 23:09
Thea Burger21-Nov-04 23:09 
GeneralRe: Tooltip Pin
Luke Foust22-Nov-04 5:20
Luke Foust22-Nov-04 5:20 
GeneralRe: Tooltip Pin
Chris Kish8-Dec-04 10:57
Chris Kish8-Dec-04 10:57 
GeneralRe: Tooltip Pin
Luke Foust8-Dec-04 11:05
Luke Foust8-Dec-04 11:05 
GeneralRe: Tooltip Pin
Chris Kish8-Dec-04 12:57
Chris Kish8-Dec-04 12:57 
GeneralTooltip Pin
Thea Burger17-Nov-04 23:37
Thea Burger17-Nov-04 23:37 
This is real cool, but I can't seem to get the Tooltip working.
I have tried your solution and created my own solution and referenced the RichListControls.dll, but nothing. Confused | :confused:
Is there something that I missed?
The style is working perfectly.


General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.