Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 825273
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 15, 20262026-05-15T03:13:43+00:00 2026-05-15T03:13:43+00:00

I have an ASP.NET Webforms site that is regularly having features added. The majority

  • 0

I have an ASP.NET Webforms site that is regularly having features added.
The majority of time a new WebControl is added to the page and I need to increment the TabIndex to all subsequent controls on the page.

I’d prefer a more robust solution than choosing an arbitrary gap between the initial assigned tab indexes. Setting the tab indexes using the designer tab order functionality is one option but I’d prefer to stay in the source view.

Ideally, if I had, for example, three check boxes I’d like to be able to define the tabindex based off the previous controls tabindex. Then I’d only need to insert the new control and change one existing control.

For example, add a new property TabIndexAfterControlId to WebControl:

<asp:CheckBox ID="checkBoxA" runat="server" TabIndex="1"/>
<asp:CheckBox ID="checkBoxB" runat="server" TabIndexAfterControlId="checkBoxA"/>
<asp:CheckBox ID="checkBoxC" runat="server" TabIndexAfterControlId="checkBoxB"/>

My first thought was to extend System.Web.UI.WebControls.WebControl with a new property, but extension properties aren’t supported.

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-15T03:13:43+00:00Added an answer on May 15, 2026 at 3:13 am

    My prior attempt using the data-binding syntax (<%# … %>) to set the TabIndex for web controls failed when some controls wouldn’t bind the TabIndex (CheckBox). It also wasn’t ideal as I needed to pass a reference to the current control into the code behind method.

    This time around I went with a custom ExpressionBuilder that accepts the name of the web control that the current control should follow in the tab order.

    The TabIndexAfterExpressionBuilder initially returns the short -1 as the value. At the same time it registers with the LoadComplete event of the current Page. When this event fires both controls are found and the tab indexes set according to their relative positions.

    Example WebControls using the TabIndex Expression Builder

    <asp:TextBox ID="txtTextBox0" runat="server" TabIndex="1" /><br />
    <asp:TextBox ID="txtTextBox1" runat="server" TabIndex="<%$ TabIndex:txtTextBox0 %>" /><br />
    <asp:TextBox ID="txtTextBox2" runat="server" TabIndex="<%$ TabIndex:txtTextBox1 %>" />
    

    TabIndexExpressionBuilder.cs

    namespace ExpressionBuilders
    {
    
        public class TabIndexExpressionBuilder : ExpressionBuilder
        {
            public override System.CodeDom.CodeExpression GetCodeExpression(System.Web.UI.BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)
            {
                string priorControlId = entry.Expression.Trim();
                string currentControlId = entry.ControlID;
    
                CodeExpression[] inputParams = new CodeExpression[] { new CodePrimitiveExpression(priorControlId),
                                                           new CodePrimitiveExpression(currentControlId),
                                                           new CodeTypeOfExpression(entry.DeclaringType),
                                                           new CodePrimitiveExpression(entry.PropertyInfo.Name) };
    
                // Return a CodeMethodInvokeExpression that will invoke the GetRequestedValue method using the specified input parameters
                return new CodeMethodInvokeExpression(new CodeTypeReferenceExpression(this.GetType()),
                                            "GetRequestedValue",
                                            inputParams);
    
            }
    
            public static object GetRequestedValue(string priorControlId, string currentControlId, Type targetType, string propertyName)
            {
                if (HttpContext.Current == null)
                {
                    return null;
                }
    
                Page page = HttpContext.Current.Handler as Page;
                if (page != null)
                {
    
                    page.LoadComplete += delegate(object sender, EventArgs e)
                    {
                        WebControl currentWebControl = FindControlRecursive(page, currentControlId);
                        WebControl priorWebControl = FindControlRecursive(page, priorControlId);
    
                        if (currentWebControl != null && priorWebControl != null)
                        {
                            TabIndexAfter(page, currentWebControl, priorWebControl);
                        }
                    };
                }
    
                // Default TabIndex
                short value = (short)-1;
                return value;
            }
    
            private static WebControl FindControlRecursive(Control rootControl, string controlID)
            {
                if (rootControl.ID == controlID) { return rootControl as WebControl; }
    
                foreach (Control controlToSearch in rootControl.Controls)
                {
                    Control controlToReturn = FindControlRecursive(controlToSearch, controlID);
                    if (controlToReturn != null)
                    {
                        return controlToReturn as WebControl;
                    }
                }
                return null;
            }
    
            #region Tabbing
    
            /// <summary>
            /// Assign the current WebControl TabIndex a value greater than the prior WebControl.
            /// </summary>
            /// <param name="currentWebControl">The current Control to set the TabIndex for</param>
            /// <param name="priorWebControl">The prior Control to get the previous TabIndex from.</param>
            /// <returns>The new TabIndex for the current control</returns>
            private static short TabIndexAfter(Page page, WebControl currentWebControl, object prior)
            {
                TabOrderWebControl tabOrderWebControl = page.FindControl("TabOrderWebControl") as TabOrderWebControl;
                if (tabOrderWebControl == null)
                {
                    tabOrderWebControl = new TabOrderWebControl();
                    page.Controls.Add(tabOrderWebControl);
                }
    
                WebControl priorWebControl = prior as WebControl;
                if (priorWebControl == null)
                {
                    string priorWebControlId = prior as string;
                    priorWebControl = page.FindControl(priorWebControlId) as WebControl;
                }
    
                if (currentWebControl == null) { throw new ArgumentNullException("currentWebControl"); }
                if (priorWebControl == null) { throw new ArgumentNullException("priorWebControl"); }
                if (currentWebControl == priorWebControl) { throw new ArgumentException("priorWebControl is the same as the currentWebControl", "priorWebControl"); }
    
                tabOrderWebControl.TabIndexAfter(currentWebControl, priorWebControl);
    
                return currentWebControl.TabIndex;
            }
    
            #endregion
        }
    }
    

    TabOrderWebControl.cs

    namespace ExpressionBuilders
    {
        public class TabOrderWebControl :
            WebControl
        {
            LinkedList<WebControl> _webControlTabOrder;
    
            internal void TabIndexAfter(System.Web.UI.WebControls.WebControl currentWebControl, System.Web.UI.WebControls.WebControl priorWebControl)
            {
                if (_webControlTabOrder == null)
                {
                    _webControlTabOrder = new LinkedList<WebControl>();
                    this.Page.PreRender += new EventHandler(PageBase_PreRender);
                }
    
                LinkedListNode<WebControl> priorNode = _webControlTabOrder.Find(priorWebControl);
                LinkedListNode<WebControl> currentNode = _webControlTabOrder.Find(currentWebControl);
    
                if (currentNode != null)
                {
                    //The current node is already in the list (it must preceed some other control)
                    //Add the prior node before it.
    
                    if (priorNode == null)
                    {
                        priorNode = _webControlTabOrder.AddBefore(currentNode, priorWebControl);
                    }
                    else
                    {
                        //Both nodes are already in the list. Ensure the ordering is correct.
                        bool foundPriorNode = false;
                        foreach (WebControl controlNode in _webControlTabOrder)
                        {
                            if (controlNode == priorWebControl)
                            {
                                foundPriorNode = true;
                            }
                            else if (controlNode == currentWebControl)
                            {
                                if (foundPriorNode)
                                {
                                    //Ordering is correct
                                    break;
                                }
                                else
                                {
                                    throw new ApplicationException(string.Format("WebControl ordering is incorrect. Found {1} before {0}", currentWebControl.ID, priorWebControl.ID));
                                }
                            }
                        }
                    }
                }
                else if (priorNode == null)
                {
                    //Neither control is in the list yet.
                    priorNode = _webControlTabOrder.AddLast(priorWebControl);
                    currentNode = _webControlTabOrder.AddAfter(priorNode, currentWebControl);
                }
                else
                {
                    //Prior node is already in the list but the current node isn't
                    currentNode = _webControlTabOrder.AddAfter(priorNode, currentWebControl);
                }
    
            }
    
            /// <summary>
            /// Once all the controls have been added to the linked list ensure the tab ordering is correct.
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            void PageBase_PreRender(object sender, EventArgs e)
            {
                AssignTabIndexes();
            }
    
            /// <summary>
            /// Reassign tab indexes for all known controls.
            /// </summary>
            protected void AssignTabIndexes()
            {
                LinkedListNode<WebControl> currentNode = _webControlTabOrder.First;
    
                while (currentNode.Next != null)
                {
                    LinkedListNode<WebControl> nextNode = currentNode.Next;
    
                    WebControl currentControl = currentNode.Value;
                    WebControl nextControl = nextNode.Value;
    
                    if (currentControl == nextControl)
                    {
                        throw new ApplicationException("Control added twice");
                    }
    
                    short currentTabIndex = currentControl.TabIndex;
                    short nextTabIndex = nextControl.TabIndex;
    
                    if (nextTabIndex <= currentTabIndex)
                    {
                        nextControl.TabIndex = (short)(currentTabIndex + 1);
                    }
    
                    currentNode = nextNode;
                }
    
            }
        }
    }
    

    web.config

    <system.web>
        <compilation debug="true" targetFramework="4.0">
            <expressionBuilders>
                <add expressionPrefix="TabIndex" type="ExpressionBuilders.TabIndexExpressionBuilder, ExpressionBuilders"/>
            </expressionBuilders>
        </compilation>
    </system.web>
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.