C# ControlCollection Extension GetAllTextboxes - asp.net

How could I get only the texboxes in a ControlCollection ?
I try :
public static IEnumerable<TextBox> TextBoxes(this ControlCollection controlCollection)
{
return (IEnumerable<TextBox>)controlCollection.Cast<Control>().Where(c => c is TextBox);
}
But I got the following error :
Unable to cast object of type 'WhereEnumerableIterator`1[System.Web.UI.Control]' to type 'System.Collections.Generic.IEnumerable`1[System.Web.UI.WebControls.TextBox]'.
I Use Asp.Net 3.5 with C#

You don't actually need a new extension method - there's already one for you that will get this:
controlCollection.OfType<TextBox>();
The OfType method returns a sequence (IEnumerable<T>) subset of the sequence provided. If the type isn't convertible, it's left out. Unlike most of the LINQ extension methods, OfType is available on sequences that aren't strongly-typed:
This method is one of the few standard query operator methods that can be applied to a collection that has a non-parameterized type, such as an ArrayList. This is because OfType<(Of <(TResult>)>) extends the type IEnumerable.
Or if you do want to wrap it in an extension method, it's of course quite simple:
public static IEnumerable<TextBox> TextBoxes(this ControlCollection controls)
{
return controls.OfType<TextBox>();
}

You want OfType():
public static IEnumerable<TextBox> TextBoxes(this ControlCollection controlCollection)
{
return controlCollection.OfType<TextBox>();
}

Here is a recursive extension method to get the Control objects that descend from the specified type, including those that are nested in the control hierarchy.
public static class ControlCollectionExtensions
{
public static IEnumerable<T> OfTypeRecursive<T>(this ControlCollection controls) where T : Control
{
foreach (Control c in controls)
{
T ct = c as T;
if (ct != null)
yield return ct;
foreach (T cc in OfTypeRecursive<T>(c.Controls))
yield return cc;
}
}
}
(For Windows Forms instead of ASP.NET, substitute Control.ControlCollection for ControlCollection.)

foreach (TextBox tBox in controls)
{
}
Example:
public static void HideControls<T>(Form pForm)
{
foreach (T cont in pForm.Controls)
{
cont.Visible = false;
}
}
HideControls<TextBox>(this);
HideControls<CheckedListBox>(this);

Related

Find all user controls that derives a specific base class, regarding of typeparam?

I´ve a base class for all user controls: SiteUserControlBase. It also takes a typeparam: SiteUserControlBase<T>. How do I best find all controls on the page that derives from SiteUserControlBase regarding of the typeparam?
I use the extension method below to find all controls of type SiteUserControlBase, but it will exclude all controls that also uses the type param.
public static IEnumerable<T> FindControlsOfType<T>(this ControlCollection Controls)
where T : class
{
T control;
foreach (Control ctrl in Controls)
{
if ((control = ctrl as T) != null)
{
yield return control;
}
foreach (T child in FindControlsOfType<T>(ctrl.Controls))
{
yield return child;
}
}
}

How do I validate list has greater than zero non null elements with MVC Attribute?

I am trying to implmenet a file uploader that can take various amounts of files. The files input elemnts are all named the same so produce a list of files that MVC3 happily binds to.
So in my controller I have have
public virtual ViewResult UploadReceive(IEnumerable<HttpPostedFileBase> Files ){
This gets all the files it should. However all empty form file input elements are adding a null. This is stopping my basic non empty List validation in the controller from working as I want.
The validation is below:
public class EnsureMinimumElementsAttribute : ValidationAttribute
{
private readonly int _minElements;
public EnsureMinimumElementsAttribute(int minElements)
{
_minElements = minElements;
}
public override bool IsValid(object value)
{
var list = value as IList;
if (list != null)
{
return list.Count >= _minElements;
}
return false;
}
}
Any idea how I change the validation to generically count only non null elements?
If you only want to count non-null objects you can use LINQ with an IList by using:
list.Cast<object>().Count(o => o != null)
Alternatively you can just loop and count each non-null object.
int count = 0;
foreach (var item in list)
{
if (item != null)
count++;
}

How to data bind Entity Framework objects to a FormView

I am data binding to many FormView controls using EF entity instances, but I have to resort to this ridiculous kludge in order to achieve what I want without using EntityDataSource controls:
propertyHeaderSection.DataSource = new List<PropertyDetailsModel> { _propertyDetails };
I suspect I will have to derive my own control from FormView and enable it to accept an almost POCO as a data source. Where do I start?
This is my implementation, sort of the same idea as patmortech, but i also found out that the ValidateDataSource method on the BaseDataBoundControl is what throws the exception at run-time if your datasource isn't enumerable.
public class CustomFormView : System.Web.UI.WebControls.FormView
{
public override object DataSource
{
get
{
if (!(base.DataSource is IEnumerable))
return new[] {base.DataSource};
return base.DataSource;
}
set
{
base.DataSource = value;
}
}
// This method complains at run time, if the datasource is not
// IListSource, IDataSource or IEnumerbale
protected override void ValidateDataSource(object dataSource)
{
//base.ValidateDataSource(dataSource);
}
}
EDIT:
Considering the suggestion, i've made some changes to the way i check if the assigned DataSource is enumerable or not. I have also managed to create a sample app (VS 2010 Solution) to demo the changes. The app can be downloaded from http://raghurana.com/blog/wp-content/attachments/FormViewDataProblem.zip
In short this is what i am checking to ensure that the existing datasource can be enumerated already or not:
public static bool CanEnumerate( this object obj )
{
if (obj == null) return false;
Type t = obj.GetType();
return t.IsArray ||
t.Implements(typeof (IEnumerable).FullName) ||
t.Implements(typeof (IListSource).FullName) ||
t.Implements(typeof (IDataSource).FullName);
}
Please feel free to suggest more changes, if this isnt quite the desired functionality. Cheers.
Not sure it's the best idea in the world, but this is how you could derive from FormView to allow single object data source values. It basically does the same check that the ValidateDataSource does internally, and then creates a list wrapper for the item if it's not already a valid type.
public class SingleObjectFormView : System.Web.UI.WebControls.FormView
{
public override object DataSource
{
get
{
return base.DataSource;
}
set
{
//will check if it's an expected list type, and if not,
//will put it into a list
if (! (value == null || value is System.Collections.IEnumerable || value is System.ComponentModel.IListSource || value is System.Web.UI.IDataSource) )
{
value = new List<object> { value };
}
base.DataSource = value;
}
}
}

Better way to find control in ASP.NET

I have a complex asp.net form,having even 50 to 60 fields in one form like there is Multiview, inside MultiView I have a GridView, and inside GridView I have several CheckBoxes.
Currently I am using chaining of the FindControl() method and retrieving the child ID.
Now, my question is that is there any other way/solution to find the nested control in ASP.NET.
If you're looking for a specific type of control you could use a recursive loop like this one -
http://weblogs.asp.net/eporter/archive/2007/02/24/asp-net-findcontrol-recursive-with-generics.aspx
Here's an example I made that returns all controls of the given type
/// <summary>
/// Finds all controls of type T stores them in FoundControls
/// </summary>
/// <typeparam name="T"></typeparam>
private class ControlFinder<T> where T : Control
{
private readonly List<T> _foundControls = new List<T>();
public IEnumerable<T> FoundControls
{
get { return _foundControls; }
}
public void FindChildControlsRecursive(Control control)
{
foreach (Control childControl in control.Controls)
{
if (childControl.GetType() == typeof(T))
{
_foundControls.Add((T)childControl);
}
else
{
FindChildControlsRecursive(childControl);
}
}
}
}
Late as usual. If anyone is still interested in this there are a number of related SO questions and answers. My version of recursive extension method for resolving this:
public static IEnumerable<T> FindControlsOfType<T>(this Control parent)
where T : Control
{
foreach (Control child in parent.Controls)
{
if (child is T)
{
yield return (T)child;
}
else if (child.Controls.Count > 0)
{
foreach (T grandChild in child.FindControlsOfType<T>())
{
yield return grandChild;
}
}
}
}
All the highlighted solutions are using recursion (which is performance costly). Here is cleaner way without recursion:
public T GetControlByType<T>(Control root, Func<T, bool> predicate = null) where T : Control
{
if (root == null) {
throw new ArgumentNullException("root");
}
var stack = new Stack<Control>(new Control[] { root });
while (stack.Count > 0) {
var control = stack.Pop();
T match = control as T;
if (match != null && (predicate == null || predicate(match))) {
return match;
}
foreach (Control childControl in control.Controls) {
stack.Push(childControl);
}
}
return default(T);
}
FindControl does not search within nested controls recursively. It does only find controls that's NamigContainer is the Control on that you are calling FindControl.
Theres a reason that ASP.Net does not look into your nested controls recursively by default:
Performance
Avoiding errors
Reusability
Consider you want to encapsulate your GridViews, Formviews, UserControls etc. inside of other UserControls for reusability reasons. If you would have implemented all logic in your page and accessed these controls with recursive loops, it'll very difficult to refactor that. If you have implemented your logic and access methods via the event-handlers(f.e. RowDataBound of GridView), it'll be much simpler and less error-prone.
Action Management On Controls
Create below class in base class.
Class To get all controls:
public static class ControlExtensions
{
public static IEnumerable<T> GetAllControlsOfType<T>(this Control parent) where T : Control
{
var result = new List<T>();
foreach (Control control in parent.Controls)
{
if (control is T)
{
result.Add((T)control);
}
if (control.HasControls())
{
result.AddRange(control.GetAllControlsOfType<T>());
}
}
return result;
}
}
From Database:
Get All Actions IDs (like divAction1,divAction2 ....) dynamic in DATASET (DTActions) allow on specific User.
In Aspx:
in HTML Put Action(button,anchor etc) in div or span and give them id like
<div id="divAction1" visible="false" runat="server" clientidmode="Static">
<a id="anchorAction" runat="server">Submit
</a>
</div>
IN CS:
Use this function on your page:
private void ShowHideActions()
{
var controls = Page.GetAllControlsOfType<HtmlGenericControl>();
foreach (DataRow dr in DTActions.Rows)
{
foreach (Control cont in controls)
{
if (cont.ClientID == "divAction" + dr["ActionID"].ToString())
{
cont.Visible = true;
}
}
}
}
Recursively find all controls matching the specified predicate (do not include root Control):
public static IEnumerable<Control> FindControlsRecursive(this Control control, Func<Control, bool> predicate)
{
var results = new List<Control>();
foreach (Control child in control.Controls)
{
if (predicate(child))
{
results.Add(child);
}
results.AddRange(child.FindControlsRecursive(predicate));
}
return results;
}
Usage:
myControl.FindControlsRecursive(c => c.ID == "findThisID");
I decided to just build controls dictionaries. Harder to maintain, might run faster than the recursive FindControl().
protected void Page_Load(object sender, EventArgs e)
{
this.BuildControlDics();
}
private void BuildControlDics()
{
_Divs = new Dictionary<MyEnum, HtmlContainerControl>();
_Divs.Add(MyEnum.One, this.divOne);
_Divs.Add(MyEnum.Two, this.divTwo);
_Divs.Add(MyEnum.Three, this.divThree);
}
And before I get down-thumbs for not answering the OP's question...
Q: Now, my question is that is there any other way/solution to find the nested control in ASP.NET?
A: Yes, avoid the need to search for them in the first place. Why search for things you already know are there? Better to build a system allowing reference of known objects.
https://blog.codinghorror.com/recursive-pagefindcontrol/
Page.FindControl("DataList1:_ctl0:TextBox3");
OR
private Control FindControlRecursive(Control root, string id)
{
if (root.ID == id)
{
return root;
}
foreach (Control c in root.Controls)
{
Control t = FindControlRecursive(c, id);
if (t != null)
{
return t;
}
}
return null;
}
The following example defines a Button1_Click event handler. When invoked, this handler uses the FindControl method to locate a control with an ID property of TextBox2 on the containing page. If the control is found, its parent is determined using the Parent property and the parent control's ID is written to the page. If TextBox2 is not found, "Control Not Found" is written to the page.
private void Button1_Click(object sender, EventArgs MyEventArgs)
{
// Find control on page.
Control myControl1 = FindControl("TextBox2");
if(myControl1!=null)
{
// Get control's parent.
Control myControl2 = myControl1.Parent;
Response.Write("Parent of the text box is : " + myControl2.ID);
}
else
{
Response.Write("Control not found");
}
}

Recursive control search with LINQ

If I wanted to find checked check boxes on an ASP.NET page I could use the following LINQ query.
var checkBoxes = this.Controls
.OfType<CheckBox>()
.TakeWhile<CheckBox>(cb => cb.Checked);
That works fine if the checkboxes are nested in the current control collection, but I'd like to know how to extend the search by drilling down into the control collections of the top-level controls.
The question was asked here:
Finding controls that use a certain interface in ASP.NET
And received non-LINQ answers, I already have my own version of a recursive control search on type and ID as extension methods, but I just wondered how easy this is to do in LINQ?
Take the type/ID checking out of the recursion, so just have a "give me all the controls, recursively" method, e.g.
public static IEnumerable<Control> GetAllControls(this Control parent)
{
foreach (Control control in parent.Controls)
{
yield return control;
foreach(Control descendant in control.GetAllControls())
{
yield return descendant;
}
}
}
That's somewhat inefficient (in terms of creating lots of iterators) but I doubt that you'll have a very deep tree.
You can then write your original query as:
var checkBoxes = this.GetAllControls()
.OfType<CheckBox>()
.TakeWhile<CheckBox>(cb => cb.Checked);
(EDIT: Changed AllControls to GetAllControls and use it properly as a method.)
public static IEnumerable<Control> AllControls(this Control container)
{
//Get all controls
var controls = container.Controls.Cast<Control>();
//Get all children
var children = controls.Select(c => c.AllControls());
//combine controls and children
var firstGen = controls.Concat(children.SelectMany(b => b));
return firstGen;
}
Now based on the above function, we can do something like this:
public static Control FindControl(this Control container, string Id)
{
var child = container.AllControls().FirstOrDefault(c => c.ID == Id);
return child;
}
My suggestion to make the AllControls recursive is:
public static IEnumerable<Control> AllControls(this Control parent)
{
foreach (Control control in parent.Controls)
{
yield return control;
}
foreach (Control control in parent.Controls)
{
foreach (Control cc in AllControls(control)) yield return cc;
}
}
The second foreach looks weird, but this is the only way I know to "flatten" the recursive call.

Resources