iterate through all tetxbox controls in a asp.net webpage - asp.net

i have 6 textboxes which i want to iterate.
they are however in a TD in a TR in a TABLE in a PANEL etc.
the only way i've figured out to iterate them is in this way:
this.Controls[0].Controls[3].Controls[7].Controls
that's not only errorprone, but also hard to come up with.
but this.FindControl (to find one by name) doesn't work either, does findcontrol also only search in the direct child, and not the whole hierarchie?
so basicly what i'm looking for is to iterate ALL controls in the page, no matter in which level of the hierarchie, to check if it's a textbox.
Is there a way to do that?
EDIT: i don't want to find them by their name (they are server controls so i could do that) because i would have to modify that code every time i add a textbox. By iterating the form i would not have to do that.

FindControl searches the hierarchy but it doesn't go into controls that are an INamingContainer
Any control that implements this interface creates a new namespace in which all child control ID attributes are guaranteed to be unique within an entire application. The marker provided by this interface allows unique naming of the dynamically generated server control instances within the Web server controls that support data binding. These controls include the Repeater, DataGrid, DataList, CheckBoxList, ChangePassword, LoginView, Menu, SiteMapNodeItem, and RadioButtonList controls.
Basically it defines a boundary to avoid naming collisions. Consider how hard it'd be if all your control IDs really had to be unique.
Note this information is also in the FindControl remarks. Tip: Always read the remarks.
The FindControl method can be used to access a control whose ID is not available at design time. The method searches only the page's immediate, or top-level, container; it does not recursively search for controls in naming containers contained on the page. To access controls in a subordinate naming container, call the FindControl method of that container.
By doing so you could navigate to the control you want going through only the naming containers & calling FindControl at each level i.e. FindControl("SomeNamingContainer").FindControl("AChildContainer")
That's not necessarily practical, and depending on what you're doing you really just need to get All TextBoxes.
IEnumerable<TextBox> TextBoxes(ControlCollection ctrls)
{
var texts = ctrls.OfType<TextBox>();
var children = ctrls.SelectMany(c => TextBoxes(c.Controls));
return texts.Union(children);
}

Try FindControl on the Page object
Page.FindControl(id)
Are they in a formview or something?
If you don't know the ID of the textboxes as well (i.e. they are dynamic) then a quick recursion code will help. I can post the code here if Page.FindControl does not work. Let me know,.
Here is the code
List<System.Web.UI.WebControls.TextBox> _textBoxes = new List<System.Web.UI.WebControls.TextBox>();
private void FindTextBoxes(ControlCollection cc)
{
foreach (Control c in cc)
{
if (c is System.Web.UI.WebControls.TextBox)
_textBoxes.Add(c as System.Web.UI.WebControls.TextBox);
else if (c.Controls.Count > 0)
FindTextBoxes(c.Controls);
}
}
You can call it as
FindTextBoxes(Page.Controls);
FindTextBoxes(MyTable.Controls);
_textBoxes collection will contain all the textboxes the code finds.
Please click the checkbox next to my answer if it solves your problem!

Related

How to get all validators in the page?

I thought RequiredFieldValidators, CustomValidators, and all other validators would live in Controls collection. Basically I have a User Control that has a number of validators in it, and I would like to get a handle on them to do stuff.
Page.Validators seem to return a list of IValidator objects, which are not what I am looking for.
Where can I get the list of all validators in a User Control?
The Page.Validators collection is your best bet; all validators implement IValidator, and in turn, BaseValidator, so you can use this do to that. Since the validator is a control, it's parent reference trail will contain a reference to the user control it lives in. It may require you doing something like:
if (validator.Parent.Parent.Parent.Parent is UserControl) { }
But that is the only way to figure that out. So a combination of Page.Validators, and checking the parent control tree is the only way, unless you look for specific validation groups that a validator implements, which also is another way (a property of BaseValidator, so you'll have to do a type check and cast.
There is one last potential option; you can override AddedControl, which executes on every control add, and check if the control is a validator, and then keep that control in a local collection like:
private List<BaseValidator> _vals = ..;
protected overrides void AddedControl(Control control, int index) {
if (control is BaseValidator)
_vals.Add((BaseValidator)control);
}
Then you would know which controls belong to that user control. I've done this with custom controls, not anything with user controls, so may not work exactly as I mentioned...
Since you're using ASP.NET validation controls you might be looking for a validation summary:
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.validationsummary%28v=vs.100%29.aspx
You can do quite a bit with it fitting most usage scenarios, here's a simple example:
http://asp-net-example.blogspot.com/2008/10/validationsummary-example-how-to-use.html
Alternatively, Page.Validators would provide direct access.

Finding an ascx control inside aspx

I'm finding a dropdown in an ascxcontrol on my aspx in the following way.
Dim cp As ContentPlaceHolder = DirectCast(Page.Form.FindControl("ContentPlaceHolder1"), ContentPlaceHolder)
Dim ascx As UserControl = DirectCast(cp.FindControl("drpType"), UserControl)
Dim drpType As DropDownList = DirectCast(ascx.FindControl("drpType"), DropDownList)
Is there a faster way without having to acces all the elements on the page?
I wouldn't try and reference a control within a user control this way, the user control should encapsulate these and the page should talk to public properties.
Depends on what you're trying to do.
Without a great deal of context, I can only assume that you are either getting or setting the value of the dropdown.
I wouldn't use the approach that you're going for. It introduces an element of implementation specific coupling.
You would be far better off exposing whatever you need to get/set via a property which you can call from the .aspx page.
However, in answer to your question, if you are going to reference the dropdown from the .aspx page, you will have to use FindControl.
If you know what naming containing the control is in you can go
ucNamingContainerControl.FindControl(controlId)
That will at least limit it to that section of the page.
Otherwise the only other thing I can think of is if you are accessing a predefined set of controls - put them in a Dictionary collection and use the Find method to pick them out. Could be a quicker retrieval but might look a bit clunky on the page.

FindControl and INamingContainer

I want to word this question carefully, so helpful people don't jump in and spend their time telling me information that I already know (I don't want to waste their time).
I want to understand how FindControl works in ASP.NET web application projects (the ones where the c# files are referenced as CodeBehind, NOT CodeFile, in the markup).
Code behind have two files which sit between the markup file. E.g. Default.aspx will have Default.aspx.cs and Default.aspx.designer.cs
If you put a button on a page, it is added to the designer file. For example:
protected global::System.Web.UI.WebControls.LinkButton LinkButton1;
If you want to get a reference to that control, it is immediately available as a member of the Default class. E.g. this.LinkButton1.Text = "Click Me";
If you look at a trace for the page, it is given a unique id as per the behaviour for INamingContainers (here, the Page): ctl00$ContentPlaceHolder1$LinkButton1
The thing I don't understand is why a null is returned by the statement:
Control c = Page.FindControl("LinkButton1");
I realise this is unnecessary, as the button is already available to the Default class. And this is because it appears as a member in the Default.aspx.designer.cs file.
The thing I do not understand is why null is returned. Because the Page implements INamingContainer, and the button has an ID which correlates to that expected of a control in an INamingContainer. Isn't this exactly the kind of thing FindControl finds?
This behaviour was new to me, maybe because i wouldn't try to search for a control that is directly accessible anyway. I think this might also be the reason why ASP.NET not even allow this, because it's faster and safer to use an existing reference than to find it (or not).
The FindControl method can be used to access a control whose ID is not
available at design time. The method searches only the page's
immediate, or top-level, container; it does not recursively search for
controls in naming containers contained on the page. To access
controls in a subordinate naming container, call the FindControl
method of that container.
http://msdn.microsoft.com/en-us/library/31hxzsdw.aspx
Edit: After i checked this behaviour, i've noticed that null is only returned if used on a Page with MasterPage, since the only control in the page's ControlCollection is the MasterPage itself.
That makes sense. You cannot guarantee an ID to be unique when the control is on the top level of a page with MasterPage, because other ContentPages might as well have a control with this ID and FindControl could today return another control than tomorrow.
If you look at the NamingContainer of the Control you want to find, you see that in case of a MasterPage it is the ContentPlaceHolder and in case of a "normal" Page it is the Page itself.
So you need to get a reference to the MasterPage's ContentPlaceholder first before you could find the control via FindControl:
Page.Master.FindControl("ContentPlaceHolder1").FindControl("LinkButton1");
http://msdn.microsoft.com/en-us/library/xxwa0ff0.aspx
FindControl is not recursive, and it looks like you have an intermediary ContentPlaceHolder1 control, which is a naming container, so this should work: Page.FindControl("ContentPlaceHolder1").FindControl("LinkButton1")
If you put it in a Panel, you can call
myPanel.FindControl("LinkButton1");

(New to ViewStates) What is the best way(s) to save a dynamically generated control into the viewstate?

I am creating a web application in Asp.net and I'm still fairly new. I'm just starting to wrap my head around the basics of the ViewState. In my application, people are searching through a database and I give them ways to narrow their search. When they have entered a valid search constraint (ex: date past 10/1/11) I dynamically add another set of controls allowing them to add another constraint. I want to save the contents of the previous constraint (a set of Controls) so that I can still have it on the webpage when they enter the next constraint.
If it makes any difference, one constraint set consists of a drop-down list of attributes, a few literal control, and one or two text fields depending on what attribute was chosen from the drop down list.
How would I go about this?
Thanks so much guys.
The easiest way to track viewstate for dynamic controls is to recreate the controls in OnInit and assign the same ID to the controls every time the page is posted back. If the controls are assigned the same ID each time they're created, when the ViewState is loaded, the controls will be repopulated.
protected override void OnInit(EventArgs e)
{
TextBox txt = new TextBox();
txt.ID = "txt1";
this.Controls.Add(txt);
}
EDIT
To make things easier, try using the DynamicControlsPlaceHolder. Just put the control on the page, and it will persist the controls and their values behind the scenes:
http://www.denisbauer.com/ASPNETControls/DynamicControlsPlaceholder.aspx
Check out this link:
https://web.archive.org/web/20210330142645/http://www.4guysfromrolla.com/articles/092904-1.aspx
http://www.codeproject.com/KB/viewstate/retainingstate.aspx
ViewState for dynamic controls is still maintained by the ASP.NET framework. Just make sure you add them during init or preinit, because viewstate is loaded for every control between the init and load stages.

user-control to nested usercontrol communication in asp.net

I have a ProductBox.ascx user control which I use as ItemTemplate for a DataList as i have to repeat it.Now that datalist in inside a seperate user control ProductGrid.ascx.There is a third usercontrol ProductPopUp.ascx.All these controls are on page User.aspx.
I want to access ProductBox.ascx from ProductPopUp.ascx. I want a loosely coupled solution to it.
Please mind ProductBox.ascx is inside other usercontrol
Create a Public property member on the nested control and set this as required for basic passing in data/values.
Edit: If these controls are repeated etc you can then set these new properties like setting other Controls using 'FindControl' and getting a reference to the UserControl.
Is this what you're after?
I understand your desire for loose coupling as user controls ideally should be solely responsible for their appearance. However I can imagine circumstances where parent controls need to dictate their childrens' behavior.
You could bubble the DataList's data binding event up to the parent page and then manipulate each product. Just try to minimize the complexity of the interface between the parents & kids putting as much business logic inside the product controls as you can.

Resources