In ASP.NET, can I convert a bunch of dropdowns into an array of dropdowns?
I have 45 dropdown lists in my asp page. There are some 开发者_如何学Gomethods that I can apply to all of these dropdowns. Is it possible to convert them into an array of dropdowns for ease of use?
I would use recursion to look for all dropdowns on your page. Based on this post it would be something like:
public static List<T> FindControls<T>(System.Web.UI.ControlCollection Controls) where T : class
{
List<T> found = new List<T>();
FindControls<T>(Controls, found);
return found;
}
private static void FindControls<T>(System.Web.UI.ControlCollection Controls, List<T> found) where T : class
{
if (Controls != null && Controls.Count > 0)
{
for (int i = 0; i < Controls.Count; i++)
{
if (Controls[i] is T)
{
found.add(Controls[i] as T);
}
else
FindControl<T>(Controls[i].Controls, found);
}
}
}
Once you have your list of dropdowns you can apply whatever methods you see fit.
Using Linq to Objects, an Extension method and Generics we can make this very concise thus:
Method Call to Get all DropDowns
var DropDowns = FindAllControlsByType<DropDownList>(MyBaseControlArray);
Find Controls Method
public static IEnumerable<Control> FindAllControlsByType<T>(IEnumerable<Control> MyCollection) where T : class
{
return MyCollection.Cast<Control>().Descendants(d => d.Controls.Cast<Control>()).Where(l => l.GetType().Equals(typeof(T)));
}
Descendants Extension Method
static public class LinqExtensions
{
static public IEnumerable<T> Descendants<T>(this IEnumerable<T> source,
Func<T, IEnumerable<T>> DescendBy)
{
foreach (T value in source)
{
yield return value;
foreach (T child in DescendBy(value).Descendants<T>(DescendBy))
{
yield return child;
}
}
}
}
EDIT
I've been looking at making this all a mite more generic so here is a completely generic solution that will traverse an object graph from a specified start point extracting all elements of the given type.
public static class Utils
{
public static IEnumerable<IEnumerable<T>> GetCollections<T>(object obj)
{
if (obj == null) throw new ArgumentNullException("obj");
var type = obj.GetType();
var res = new List<IEnumerable<T>>();
foreach (var prop in type.GetProperties())
{
// is IEnumerable<T>?
if (typeof(IEnumerable<T>).IsAssignableFrom(prop.PropertyType))
{
var get = prop.GetGetMethod();
if (!get.IsStatic && get.GetParameters().Length == 0) // skip indexed & static
{
var collection = (IEnumerable<T>)get.Invoke(obj, null);
if (collection != null) res.Add(collection);
}
}
}
return res;
}
public static IEnumerable<V> FindAllControlsByType<V, T>(V MyCollection) where T : class
{
return Utils.GetCollections<V>(MyCollection).Descendants(d => d).Where(l => typeof(T).IsAssignableFrom(l.GetType()));
}
}
static public class LinqExtensions
{
static public IEnumerable<T> Descendants<T>(this IEnumerable<IEnumerable<T>> source,
Func<IEnumerable<IEnumerable<T>>, IEnumerable<IEnumerable<T>>> DescendBy)
{
foreach (IEnumerable<T> collection in source)
{
foreach (T value in collection)
{
yield return value;
foreach (T child in DescendBy(Utils.GetCollections<T>(value)).Descendants<T>(DescendBy))
{
yield return child;
}
}
}
}
}
And we can call that using:
var DropDowns = Utils.FindAllControlsByType<Control, DropDownList>(BaseControl);
Basically the two types are the base class and the specific child class that you want to extract. You'll notice that the process identifies all collections of the base class that are contained within each instance of the base class. This means we're not tied to Controls
as the collection and could use this within other structures. Any additional optimisations welcomed.
精彩评论