Customizing the processing of ListItems for asp:RadioButtonList with "Flow" layout and "Horizontal" direction

Hi,

recently I was asked to add an ability to pad specific elements from each other to a certain distance in RadioButtonList control. Not quite common everyday task I would say :)

 

Ok, let's get started!

 

Prerequisites:

ASP.NET Page having RadioButtonList control with RepeatLayout="Flow" RepeatDirection="Horizontal" properties set.

 

Implementation: 

The underlying data was coming from another source, so the only fast way to add meta information about padding was the text value itself (yes, not very optimal solution):

Id = 1, Name = "This is first element" and for padding we agreed to use <space/> meta tag: Id = 2, Name = "<space padcount="30px"/>This is second padded element"

 

To handle items rendering in RadioButtonList control I've created custom class and subclassed from it:

 

 public class CustomRadioButtonList : RadioButtonList
    {
        private Action<ListItem, HtmlTextWriter> _preProcess;

        protected override void RenderItem(ListItemType itemType, int repeatIndex, RepeatInfo repeatInfo, HtmlTextWriter writer)
        {
            if (_preProcess != null)
            {
                _preProcess(this.Items[repeatIndex], writer);
            }

            base.RenderItem(itemType, repeatIndex, repeatInfo, writer);
        }

        public void SetPrePrenderItemFunction(Action<ListItem, HtmlTextWriter> func)
        {
            _preProcess = func;
        }
    }

 

It is pretty straightforward approach, the key is to override RenderItem method. Class has SetPrePrenderItemFunction method which is used to pass custom processing function that takes 2 parameters: ListItem and HtmlTextWriter objects.

 

Now update existing RadioButtonList control in Default.aspx:

add this to beginning of the page:

 

<%@ Register Namespace="Sample.Controls" TagPrefix="uc1" %>

 

and update the control to:

 

<uc1:CustomRadioButtonList ID="customRbl" runat="server" DataValueField="Id" DataTextField="Name"
            RepeatLayout="Flow" RepeatDirection="Horizontal">
</uc1:CustomRadioButtonList>

 

Now, from codebehind of the page:

 

Add regular expression that will be used for parsing:

 

private Regex _regex = new Regex(@"(?:[<]space padcount\s*?=\s*?(?:'|"")(?<padcount>\d+)(?:(?:\s+)?px)?(?:'|"")\s*?/>)(?<content>.*)?", RegexOptions.IgnoreCase | RegexOptions.Compiled);

 

and finally setup the processing function in Page_Load:

 

protected void Page_Load(object sender, EventArgs e)
    {
        customRbl.DataSource = DataObjects;

        customRbl.SetPrePrenderItemFunction((listItem, writer) =>
        {
            Match match = _regex.Match(listItem.Text);
            if (match.Success)
            {
                writer.Write(string.Format(@"<span style=""padding-left:{0}"">Extreme values: </span>", match.Groups["padcount"].Value + "px"));

                // if you need to pad listitem use code below
                //x.Attributes.CssStyle.Add("padding-left", match.Groups["padcount"].Value + "px");

                // remove meta tag from text
                listItem.Text = match.Groups["content"].Value;
            }
        });

        customRbl.DataBind();
    }

 

That's it! :)

 

Run the attached sample application:

 

 

P.S.: of course several other approaches could have been used for that purpose including events and the functionality for processing could also be embedded inside control itself.

Current solution suits slightly better due some other reasons for situation where it was used, in your case consider this as a kick start for your own implementation :)

 

Source application: CustomRadioButtonList.zip

No Comments