Foreach loop and placeholders - asp.net

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.

Related

How to use "strongly typed data table" (or "row") in WebForms code-behind?

Our asp.net WebForms application is using table-adapters for "strongly typed data tables" and data-rows. In the code-behind I find I cannot use the return value directly from the BLL-class instance (such as our "Main_TblAdap.CostDataTable") as in referring to the strongly-typed data-rows and columns/fields within.
What is the proper way to make use of the strongly-typed data-table or data-row within the code behind events and methods?
Further, we want the ability to reference a specific data-row or sort/filter the data-table.
A good coding example would be very helpful showing the best way to (1) get from a strongly-typed data-table to reference values in a specific data-row from within the data-table and (2) how to sort/filter the strongly-typed data-table.
First create a DataView from the Table. You can either customize the view on initialization or call get default.
DataView dv = yourTable.DefaultView;
Or go ahead and filter the view from the table when you create your reference pointer like so:
DataView custDV = new DataView(YourTable[yourTableName],
"VehicleID = 'xxx'", // Row filter
"VehicleID", // Sort
DataViewRowState.CurrentRows);
Now you can sort the View and filter by Row state
dv.Sort();
view.RowStateFilter = DataViewRowState.Added |
DataViewRowState.ModifiedCurrent;
ROWS.
You can interact with the DataRowView IEnumerable within the DataView.
foreach (DataRowView rowView in thisDataView)
{
// your code here
}
OR
foreach(DataRow r in dt.Rows)
{
// your code here
}
To find rows in the table try:
var result = dt.AsEnumerable().Select(r => r["Id"] = 4);
if(result !=null)
{
int x = 0;
}
Now just bind to your view and if you add a row or update it, the view gets updated as well.

Bind multiple dropdownlists to same datasource using loop

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...

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.

ASP Multiselect listbox separator

I have encountered a problem and I didn't manage to find any soultions yet. Let me simplify things a bit.
I have 2 forms, the first contains an ASP ListBox with multi select mode enabled. I submit the form and in the other form I use just for testing purposes this snippet of code:
protected void Page_Load(object sender, EventArgs e)
{
foreach (string formKey in Request.Form.AllKeys)
{
if (formKey != null)
{
if (formKey.Equals("ctl00$MainContent$ListBox1"))
Label1.Text = Request.Form[formKey];
}
}
}
The problems is that the values that come from the listbox (the values that i selected in the previous form) are separated by "," for ex. "test1,test2,test3". How can i change this separator to "$" for example? I need to change it because the actual values may contain "," and i don't manualy feed them to the listbox.
I can't use any other mode of transfering this values between the form because the entire application uses this model. The values that i get are then sent to a workflow where there will be manipulated and in the workflow i need to know where each listbox item starts and ends so it must be an unique separator.
Any help is apreciated! Thank you very much
Thank you MatteKarla but unfortunately this does not solve my problem. Yes, this is a good way of transfering the values from one form to another.
However i must use the method I described above with Request form keys because the listbox is one of many others "parameters" that are generated at runtime and have their values sent to a workflow method that takes this values. And i can't afford to change that in my application.
My problem is that coma (",") separator is used by default with a multiselect listbox.
I thought that there maybe is a method to change that separator from coma to another char because the coma can also be included in the value itself and this will create confusion.
As i said if i select three values test1, test2 and test3, the result with my method will be a string looking like "test1,test2,test3". However a "test1$test2$test3" would be much better.
But I'm affraid that changing this default separator is not possbile. I must think at a method to overcome this problem like replacing before feeding the listbox all the intended coma from the values with some other char not to create confusion. But this is not a great way of doing it.
On your first page/form (First.aspx.cs) create a public property with the listbox:
public ListBox PostedListBox { get { return ListBox1; } }
Set the postback-url for the button to Second.aspx
Second page in the aspx-file after the #Page-directive add:
<%# PreviousPageType VirtualPath="~/First.aspx" %>
Then in Form_Load on Second.aspx.cs you can extract the values:
if (PreviousPage != null)
{
ListBox postedListbox = PreviousPage.PostedListBox;
foreach (var index in postedListbox.GetSelectedIndices())
{
var itemText = postedListbox.Items[index].Text;
}
}
Or you could just try to locate the control by using:
if (PreviousPage != null)
{
var control = PreviousPage.FindControl("ListBox1") as ListBox;
}
Third Edit:
You could use GetValues:
Request.Form.GetValues("ctl00$MainContent$ListBox1");
returns a string array containing each of the selected items.

ASP.NET Dynamic Data setting the default value of a Dropdown list

I have a dropdown list (FK) which I would like to set and display a default value based on a login userid. Can you please tell me how to do it? I only want to affect the dropdown filter that appear at the top above the Gridview.
Thanks
Nikos
If you only want this functionality in the DropDown list that appears in the Filter Criteria section, just modify the URL by adding the QueryString parameters you would like to filter by. The DynamicFilter will pick up the values from the QueryString and set the DropDown lists accordingly. (fyi. this is the same functionality that the ForeignKey.ascx FieldTemplate provides)
It would be nice if there was a better way to actually create this URL (instead of using string), but as of right now, any solution I provide is probably going to break in a subsequent version.
example (in page_load)
Response.Redirect("~/Employees/List.aspx?ReportsTo=1234");
Is this a universal change, or just for one foreign key relationship?
Assuming it is for just one foreign key relationship, you could create a new FieldTemplate, to be used just for that relationship. The New FieldTemplate would be a copy of the default "ForeignKey" FieldTemplate. In the New FieldTemplate modify the OnDataBinding (or Page_PreRender) event to set the "default value" of the DropDownList.
Then, to force the New FieldTemplate to be used for that relationship, you would need to use the System.ComponentModel.DataAnnotations.UIHint attribute on the member of your Entity Class that represents that foreign key relationship. (links below)
http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.uihintattribute.uihint.aspx
or http://www.asp.net/learn/3.5-SP1/video-291.aspx (around 07:30 mins)
For a little help, you could take a look at the DynamicData Futures release on CodePlex. Specifically the "Populate Insert templates with values from filters" section. http://www.codeplex.com/aspnet/Release/ProjectReleases.aspx?ReleaseId=14475
I have figured out a workaround, but am open to a more elegant solution.
I edited the FilterUserControl.ascx.cs by inserting the following line in the Page_Init after PopulateListControl(DropDownList1);
DropDownList1.SelectedIndex = DropDownList1.Items.IndexOf(DropDownList1.Items.FindByText("Bob")); // Username is hardcoded just for test
This seems to work but I would prefer using the custom Partial Entity Class with metadata to solve this if possible.
I have solved this in an application I am working on, in your insert view template code behind:
In ItemCreated event for the details view:
foreach (DetailsViewRow row in DetailsView1.Rows)
{
foreach (Control ctl in row.Controls)
foreach (Control c in ctl.Controls)
foreach (Control x in c.Controls)
{
if (x.ClientID.Contains("tblName"))
{
foreach (Control y in x.Controls)
{
if (y.ClientID.Contains("DropDownList"))
{
ddl = y as DropDownList;
ddl.SelectedValue = Convert.ToString(UserId);
ddl.Enabled = false;
}
}
}
}
}
With this code, when a user is logged in and they go to insert some entity (tblName) the drop down list (fk to userId) is already selected and disabled.

Resources