Bind multiple dropdownlists to same datasource using loop - asp.net

I have a form with 15 dropdownlists inside a table. I would like populate each ddl with the same values from a single datasource.
Instead of doing the below x 15:
ddl.datasource = x
ddl.databind()
Is it possible to loop through all the DDL's in a table and assign the datasource etc all in one go?
Something like this? (I know the code is wrong but I am unsure of the full correct code)
For Each ctrl In tblNetwork.Controls
If TypeOf ctrl Is DropDownList Then
ddl.DataSource = usr
ddl.DataBind()
End If
Next ctrl
Seems a basic one but it's got me stumped.

You are getting stumped because your method is only going to traverse the top-level controls since iterating over tblNetworks.Controls won't be recursive.
I think that this is, in general, a very bad idea because your page will suffer from the recursion that you need to make in order to catch all the dropdowns in the page. With that said, here's a solution (in C#, sorry) that will work, regardless of the level of nesting of your dropdown lists.
First, you need to create a helper method that flattens any IEnumerable so we can use LINQ:
public static class ControlExtensions
{
public static IEnumerable<T> Flatten<T>( this IEnumerable<T> e, Func<T, IEnumerable<T>> f)
{
return e.SelectMany(c => f(c).Flatten(f)).Concat(e);
}
}
And now your code becomes this:
var result = this.Controls.Cast<DropDownList>().Flatten(x=>x.Controls.Cast<DropDownList>());
DropDownList current;
foreach (var item in result)
{
if (item is DropDownList)
{
current = item as DropDownList;
current.DataSource = your_data_source;
current.DataBind();
}
}
You can obviously extend this further to do the same on any page you need to, but the more complicated your page is, the bigger your performance hit.
I hope I persuaded you from doing this...

Related

Foreach loop and placeholders

I have a placeholder in my .aspx file
When i add controls to in in the .aspx.cs file i also add some literal controls in addition to some tableboxes and labels, as such
phOutputs.Controls.Add(new LiteralControl("<tr><td>"));
phOutputs.Controls.Add(lbl1);
phOutputs.Controls.Add(new LiteralControl("</td><td>"));
phOutputs.Controls.Add(tbx1);
phOutputs.Controls.Add(new LiteralControl("</td></tr>"));
Down the road i tried using a foreach loop as like this
foreach (TextBox tbxInput in phOutputs.Controls)
but i get cast exceptions on run time saying you cant convert LiteralControl to tablebox.
What would be a better way of doing this?
The error is because your collection contains not only textboxes.
OfType extension can be used for filtering.
foreach (TextBox tbxInput in phOutputs.Controls.OfType<TextBox>())
{
}
Also as alternative - you can make a cast to a base class WebControl (instead of TextBox) in your foreach, but it depends on what you want to do in this loop. For sure, if you need textbox specific properties - this variant won't do.
You should first check whether the control is of type TextBox or not and then cast it to Textbox accordingly
foreach (control crtl in phInputs.Controls)
{
if(crtl is TextBox )
{
TextBox txt = (TextBox )crtl;
}
}
If you're trying to just loop over textboxes, you can use Linq to select only the controls that are textboxes and then iterate over those instead:
foreach(TextBox tbxInput in phOutputs.Controls.Where(o => o is TextBox))
Voila; no InvalidCastException.

asp.net dynamic controls values

I am trying to create a poll system that will ask the users for the number of options they would like to add from a dropdownlist.
Then when the user choose a number i would like to add text-boxes for those numbers and finally use asp.net to iterate through the text-boxes and add their values in the database.
Example:
User chooses to add 5 options.
I use Jquery to to append 5 inputs to the form.
User adds their values.
I iterate through the text-boxes and execute a void based on these
values.
i am able to do the first 3 steps but i am stuck on the 4th step. To solve it i tried to use a loop:
foreach (TextBox tb in form1.Controls)
{
Response.Write(tb.Text);
}
but that throws an error:
Unable to cast object of type 'System.Web.UI.LiteralControl' to type 'System.Web.UI.WebControls.TextBox'.
how can i iterate throw the text-boxes?
thanks
Any static content is represented by a LiteralControl, which is why you experience that. A real easy way is to use LINQ:
var ctls = form1.Controls.OfType<TextBox>();
foreach (var ctl in ctls) { .. )
Or check the type as you loop through the controls to make sure it's a textbox first:
foreach (Control tb in form1.Controls)
{
if (tb is TextBox)
Response.Write(((TextBox)tb).Text);
}
Brian's answer seems a solid one. Another option that comes to mind at first sight is:
Declare a function...
Declare a simple array or even a string in js
Iterate from client side your inputs
And for each iteration you should be saving the value in that array or concatenating the value.
The array then can be saved as a string in some asp hiddenfield in order to do your server-side stuff.
Best regards.

Avoid "magic strings" in databound web controls?

Is there a way to bind data to controls using the properties being bound to them so re-factoring and typos aren't so much of an issue?
For example, instead of assigning field names to a drop-down list like ddl.DataTextField = "FieldName"; ddl.DataValueField = "Id", I would hypothetically write ddl.DataTextField = MyClass.FieldName; ddl.DataValueField = MyClass.Id;.
Edit:
I'm thinking about having my objects implement an interface that has DataTextField and DataValueField (or similarly named) properties so, at the very least, my DDLs would be consistently bound.
This wouldn't help in the case of ListViews, GridViews, etc. though.
I am not sure if this is what you are thinking, but maybe it will help out.
private void PopulateDropDown( List<MyClass> myClassList )
{
// Loop through myClassList.
foreach ( MyClass m in myClassList )
{
// Add myClass to the drop down list.
ListItem item = new ListItem( m.FieldName, m.Id.ToString() );
ddl.Items.Add( item );
}
}

item.selected Not working in ListBox

I have this piece of code:
foreach (ListItem item in lbUnassigned.Items)
{
if (item.Selected)
{
string itemName = item.Text.ToString();
string itemValue = item.Value.ToString();
lbAssigned.Items.Add(new ListItem(itemName, itemValue));
lbUnassigned.Items.Remove(lbUnassigned.SelectedItem);
}
}
Which is pretty much identical to an example given in the .NET 3.5 book I have, yet when stepping through this procedure the item.selected if false every time, even though I am selecting at least one value in the ListBox.
Any ideas what I could be doing wrong?
Usually when something like this happens the reason is control rebinding. Check if you have the if(!IsPostBack) on your page load when binding the control

Accessing asp.net tablerow child control by type

I'm iterating through a collection of asp:tablerows to be able to get or set the text in a textbox that is nested in the third cell of the row; I'm doing this by type rather than by ID because the cell ID's in that column aren't totally consistent--thus I can't really call FindControl() to achieve this. I've resorted to casting the third control in the TableRow to a TableCell and then Casting the first control in that cell to a TextBox. Not quite correct, as I'm getting an index out of range exception thrown. The problem mainly lies in the Controls.Count() property of the third cell, which comes to zero.
Not sure if there's a better way to access the textbox---should I resort to FindControl()?
The code:
foreach (TableRow row in tblProviders.Rows) {
string value = ((TextBox)((TableCell)row.Controls(2)).Controls(0)).Text;
...
}
My searches here only yielded use of FindControl(), so that may be the only way...
Thanks!
You could use Linq as follows:
var TextBoxes = tblProviders.Rows.OfType<TableRow>()
.SelectMany(row => row.Cells.OfType<TableCell>()
.SelectMany(cell => cell.Controls.OfType<TextBox>()));
TextBoxes would then be a collection of all the textboxes in tblProviders.Rows, which you could then itterate through and do what you like with.
A little bit of null checking wouldn't go amiss here.
You could try using this Recursive call:
foreach (TableRow row in tblProviders.Rows) {
var tb = FindControlRecursive(row, typeof(TextBox));
if (tb != null) {
string value = ((TextBox)tb).Text;
}
}
private Control FindControlRecursive(Control rootControl, Type controlType) {
if (rootControl.GetType() == controlType)
return rootControl; //Found it
foreach (Control controlToSearch in rootControl.Controls) {
Control controlToReturn = FindControlRecursive(controlToSearch, controlType);
if (controlToReturn != null) return controlToReturn;
}
return null;
}

Resources