Better FindControl for ASP.NET

There is one main limitation with FindControl in ASP.NET: it only looks in the NaminingContainer of the control you are searching within. Here is a better, much improved version of FindControl for ASP.NET written in C# as an extension to the Control class called DeepFind.

The code scans both up and down the control hierarchy from the current control. The control nearest to the current control with the given control ID is returned.

Deep Find Algorithm

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.UI;

public static class ControlExtensions
{
   public static Control DeepFind(this Control owner, string controlId)
   {
      return DeepFind<Control>(owner, controlId);
   }

   public static TType DeepFind<TType>(this Control owner, string controlId)
      where TType : Control
   {
      if (owner is TType && String.Equals(owner.ID, controlId,
            StringComparison.InvariantCultureIgnoreCase))
      {
         return (TType)owner;
      }

      IEnumerable<Control> controls = owner.Controls.Cast<Control>();

      Control parent = owner.Parent;

      if (parent != null)
      {
         controls = controls.Concat(parent.Controls.Cast<Control>()
            .Where(control => control != owner));
      }

      while (controls.Any())
      {
         foreach (TType control in controls.OfType<TType>())
         {
            if (control is TType && String.Equals(control.ID, controlId,
               StringComparison.InvariantCultureIgnoreCase))
            {
               return control;
            }
         }

         controls = controls.SelectMany(child => child.Controls.Cast<Control>());

         if (parent != null)
         {
            Control grandParent = parent.Parent;

            if (grandParent != null)
            {
               controls = controls.Concat(grandParent.Controls.Cast<Control>()
                  .Where(control => control != parent));
            }

            parent = grandParent;
         }
      }

      return null;
   }
}