ASP.NET FindControl Recursive with Generics
While working on the new version of Channel 9, part of my job this time around was to "templatize" our entire community platform. The way everything is set up now, aspx files are read in through the Virtual Path Provider (VPP), additional settings in the Page directive are set based off of database settings and the page is rendered. All our controls are now ascx files with the CodeFileBaseClass set to a class that implements all the code. This allows us to easily setup new controls and templates for our different sites if new ones are needed. Right now, Channel 9 and Channel 10 are the only two sites that will be running this code. In the halfway near future, VisitMIX and a yet to be named Student focused site will run this code as well, so templating was very important. My other job for this sprint was to add ASP.NET AJAX functionality to the site. As we get closer to launching the beta you'll see more posts from me sampling some of our code and techniques especially around ASP.NET AJAX.
The new EntryList control that I created takes a List<Entry>. The control has a setting to let us set which ascx file we want to use to represent each Entry in the list. These are loaded using Page.LoadControl. The same thing goes for the Pager and Filters control in the header and footer of the EntryList. All of these controls implement different interfaces so we can throw in different ones and look them up generically. I don't necessarily know the names of these controls and needed a way to look them up by the interfaces they implement. So I thought, "hey, I'll bet generics could help me out here." I got the below code written, but unfortunately couldn't figure out how to properly cast the control by the type passed in. My next door neighbor, our resident Sampy, helped me figure out that I needed to force the type coming in to be a reference (hence the "where T : class" part). Here's the resulting code...
public static T FindControl<T>(System.Web.UI.ControlCollection Controls) where T : class
T found = default(T);
if (Controls != null && Controls.Count > 0)
for (int i = 0; i < Controls.Count; i++)
if (Controls[i] is T)
found = Controls[i] as T;
found = FindControl<T>(Controls[i].Controls);
Unlike a recursive method that's not generic, you would have to pass in the type as a parameter to the method, which would get passed down through every method call, and you'd have to cast the found control on every call you made to FindControl. That wouldn't be a huge deal, but there is something nice about simplicity. :)
IMyInterface myControl = FindControl<IMyInterface>(this.Controls);
Note: This only returns the first instance of a control. You could easily pass in a references List<IMyInterface> and add to it as you find them.
This isn't break through code or anything, but it's fun for us, the dev geeks. Expect to see more posts soon about coding techniques in our platform.