On default.aspx I have the following hidden fields:
<asp:HiddenField runat="server" ID="icon1" />
<asp:HiddenField runat="server" ID="icon2" />
<asp:HiddenField runat="server" ID="icon3" />
As you can see, the name of the field is the same each time but increments by 1 up to 3.
In my code behind I have been doing this (if statements and other code removed for brevity - this is the meat of it):
icon1.Value = "Bonus1";
icon2.Value = "Bonus2";
icon3.Value = "Bonus3";
Must I assign the iconX.Value individually every time like that? Can I do it all in one shot in a loop (also with everything else removed for brevity)?
for (int i = 1; i <=3; i++)
{
icon(i).Value = "Bonus" + i.ToString();
}
Everything I have read leads me to believe this is not possible in C#. Let's pretend I have 50 iconX.Value = whatever to assign. A loop makes the most logical sense. Possible?
A loop makes the most logical sense. Possible?
Yes. Use the FindControl method of the page to look up a control by its ID:
for (int i = 1; i <= 3; i++)
{
HiddenField field = (HiddenField)this.FindControl("icon" + i);
field.Value = "Bonus" + i.ToString();
}
Note: Because the return type of FindControl is Control, you must cast the result in order to access properties specific to HiddenField.
You have to create a asp:panel in the HTML section.
Then, in the c# code, make a loop and create elements like you describe.
When the element is fully configured, add it to the panel.
.ASPX file
<asp:Panel ID="panel_controls" runat="server"> </asp:Panel>
C# code
for (int i = 1; i <= 3; i++) {
HiddenField myField = new HiddenField();
myField.ID = "icon" + i;
myField.Value = "Bonus" + i;
panel_controls.Controls.Add(myField);
}
Related
I am simply trying to create a list and add elements to it from the code behind. Each list element must be connected to a function in the code behind so I am using the Asp:LinkButton to do this. In the Default.aspx page I have:
<asp:ListView ID="ulNumTenants" runat="server">
<ItemTemplate>
<li>
<%# DataBinder.Eval(Container.DataItem, "XXX" ) %>
</li>
</ItemTemplate>
</asp:ListView>
And in the code behind I have the following:
var listItems = new List<LinkButton>();
int numberOfTenantsPossible = Space.MaxNumberOfTenants - (Space.MaleHousemates + Space.FemaleHousemates);
for (int itemCount = 0; itemCount < numberOfTenantsPossible; itemCount++ )
{
LinkButton currentItem = new LinkButton();
currentItem.CommandArgument = (itemCount + 1).ToString();
currentItem.CommandName = "Tenant_OnClick";
currentItem.Text = (itemCount + 1).ToString() + " tenants";
listItems.Add(currentItem);
}
ulNumTenants.DataSource = listItems;
ulNumTenants.DataBind();
The issue I am having is in the default.aspx code since I do not know what the expression field( "XXX" ) should be set to when I am not getting the entries from a database. Any suggestions are greatly appreciated.
Try this:
<%# Container.DataItem %>
I doubt it will work, since I think it will just take the string representation of a LinkButton instead of the HTML markup. However, why create the LinkButton dynamically in code? Try this instead:
Code Behind:
public class TenantViewModel
{
public string ID {get; set;}
public string Name {get; set;}
}
int numberOfTenantsPossible = Space.MaxNumberOfTenants - (Space.MaleHousemates + Space.FemaleHousemates);
var vms = new List<TenantViewModel>();
for (int itemCount = 0; itemCount < numberOfTenantsPossible; itemCount++ )
{
var vm = new TenantViewModel { ID = (itemCount + 1).ToString(), Name = (itemCount + 1).ToString() + " tenants"};
vms.Add(vm);
}
ulNumTenants.DataSource = vms;
ulNumTenants.DataBind();
ASPX:
<asp:ListView ID="ulNumTenants" runat="server">
<ItemTemplate>
<li>
<asp:LinkButton runat="server" CommandName="Tenant_OnClick" CommandArgument='<%# (Container.DataItem as TenantViewModel).ID' Text='<%# (Container.DataItem as TenantViewModel).Name' />
</li>
</ItemTemplate>
</asp:ListView>
That allows you to keep UI element declaration in your ASPX markup, and instead of creating all the buttons in your code behind, you just create a view model to bind it to. Container.DataItem will be an object, so we use the as syntax to convert it to the correct type TenantViewModel so we can access the properties. This results in much cleaner code. Instead of a ListView, you might also consider binding to a Repeater. ListViews are typically for two way binding directly to a database, but we're binding to a custom IEnumerable.
Also, if you do find that this markup is significantly cleaner, you might consider looking into ASP.NET MVC. The markup gets even cleaner there with Razor syntax, because you won't have to worry about casting to the correct type. Instead of using a repeater, you'd just use a foreach loop.
This scenario is occurring when using C# code behind to find HTML Controls added dynamically from SQL Data Results.
Using the following there is an iteration though the Table rows and row each table row, we write the Controls value, in this case a HtmlSelect. The Html Select Element is in Cell 3
for (int i = 1; i <= Table1.Rows.Count - 1; i++)
{
HtmlSelect select = Form.FindControl("MainContent_selectBoxstatus" + i) as HtmlSelect;
System.Diagnostics.Debug.Write(select.Value);
}
Resulting in:
A first chance exception of type 'System.NullReferenceException'
occurred in project.dll
If i use the following:
for (int i = 1; i <= Table1.Rows.Count - 1; i++)
System.Diagnostics.Debug.Write(Table1.Rows[i].Cells[0].Text);
I get the desired result, of the text from Cell 1.
How the Select Dropdown is created:
for (int i = 0; i < dr.FieldCount; i++)
HtmlSelect sStatus = new HtmlSelect();
sStatus.Items.Add(new ListItem("Working", "0"));
sStatus.Items.Add(new ListItem("Fault", "1"));
sStatus.SelectedIndex = 0;
sStatus.Attributes.Add("class", "dropdownlist");
sStatus.ID = "selectBoxstatus" + rowindex;
cell.Controls.Add(sStatus);
That's what usually happens when you are trying to "hack" ASP.NET internals. I mean "hack" because using magic strings to resolve the auto-generated ids assigned to child controls is extremely unsafe. There are much better and safer ways to do this.
1- If you want to render a tabular layout, I'd strongly recommend using a databound control such as a GridView, ListView, etc where you can intersect its RowDatabound event and retrieve the child controls in a safe manner
2- If you can't afford to do a re-write then replace your code as follows...
for (int i = 0; i < Table1.Rows.Count; i++)
{
HtmlSelect select = Table1.Rows[i].Cells[0].FindControl(string.Format("selectBoxstatus{0}", i)) as HtmlSelect;
if(select != null)
System.Diagnostics.Debug.Write(select.Value);
}
Option 2 Code Analysis
for (int i = 0; i < Table1.Rows.Count; i++)
Nitpicking, but initializing i to 0 this makes it easier to read...believe it
HtmlSelect select = Table1.Rows[i].Cells[0].FindControl(string.Format("selectBoxstatus{0}", i)) as HtmlSelect;
I'm not too sure what Form meant in your original post but it makes more sense to use the object you're iterating....Table1 rows collection. I also refer to Cell[0] which is the first cell in the iteration's current row(feel free to adjust it)...this is still not safe but it's the only way to achieve it in the current scenario, if you need more code safety, then resort to option one. Also notice that FindControl doesn't mess around with auto-generated id, it simply uses the actual Id specified for the child control
if(select != null)
After you attempt to retrieve the select control make sure to check whether the control was successfully retrieved or not.
Hope it makes sense
Try changing your loop so that you call findcontrol on the row instead:
for (int i = 1; i <= Table1.Rows.Count - 1; i++)
{
HtmlSelect select = Table1.Rows[i].FindControl("MainContent_selectBoxstatus" + i) as HtmlSelect;
}
I have a drop down list that comes from a sqldatasource that is presented in alphabetical order. Because of this, the lists index numbers do not line up at all with the primary keys within the SQL table. I need to be able to set the drop down list's selection on page load based on primary key information I have.
<asp:DropDownList ID="catagoryDropDown" runat="server" DataSourceID="SqlDataSource3"
DataTextField="Catagory" DataValueField="PK_SupportCatagory" CssClass="dropDownList">
</asp:DropDownList>
<asp:SqlDataSource ID="SqlDataSource3" runat="server" ConnectionString="<%$
ConnectionStrings:ApplicationServices %>"
SelectCommand="SELECT [PK_SupportCatagory], [Catagory] FROM [SupportCatagory] ORDER BY CASE
WHEN [PK_SupportCatagory] = 1 THEN 1 ELSE 2 END, [Catagory]">
</asp:SqlDataSource>
My thought is to get the string by querying the database using that to set the drop down list appropriately.
catagoryDropDown.SelectedValue = "Sick Leave";
The above does not work. How would I accomplish this? Is there a better way to do this?
Garrison Neely's answer did not quite work but it got me on the right track. This ultimatly worked:
int i = 0;
foreach (var item in catagoryDropDown.Items)
{
if (item.ToString().Equals("Sick Leave"))
{
catagoryDropDown.SelectedIndex = i;
break;
}
i++;
}
var selectedIndex = -1;
for(int i = 0; i < catagoryDropDown.Items.Count; i++)
{
if(catagoryDropDown.Items[i].Text.ToLower() == "sick leave")
{
selectedIndex = i;
break;
}
}
if(selectedIndex > -1)
{
catagoryDropDown.SelectedIndex = selectedIndex;
}
Added the .ToLower() because it makes things easier when strings don't have case worries.
Try this:
catagoryDropDown.SelectedValue = catagoryDropDown.Items.FindByText("Sick Leave").Value;
Try this One, I am pretty sure it will work:
ddl.SelectedIndex = ddl.Items.IndexOf(ddl.Items.FindByText(Convert.ToString(Any Value)));
Make sure the value exist in the datasource (to which the ddl is bound) before.
I have a GridView asp server control in a page and I have set its AllowPaging to true. Now, I want to loop to the entire rows but it only iterates to the number of PageSize that I have defined.
Here is the asp code:
<asp:GridView ID="gvName" runat="server" AllowPaging="True" PageSize="5" AutoGenerateColumns="True"></asp:GridView>
Here is the code behind:
List<string> list = new List<String>();
for(int x = 0; x <= 9; x++)
{
list.Add("Name " + (x + 1).ToString());
}
gvName.DataSource = list;
gvName.DataBind();
foreach(GridViewRow row in gvName.Rows)
{
// gvName.Rows.Count only returns 5 instead of the total number of its record that is 10
}
Thanks in advance for any kind of answer.
That's a feature, not a bug, of how the paging works-- it only loads x rows for each page load. Depending on what you need to accomplish, you could either:
Cycle through the rows on every page load (since you should only care about the visible ones anyway, right?)
Cycle through the actual data source, either using your list object, or GridView.DataSource (casting to the appropriate type first).
Use the grid event OnRowDataBound event to do all the work you want with the rows
to get the count use:
int count = list.Count;
when i execute the code i get 4 checkboxs and i checked/selected all 4 checkbox and when i try to debug the code, it does count that i have 4 checkbox but all 4 checkbox is selected=false.
what i am missing in code?
<asp:checkboxlist id="chk" runat="server" ondatabinding="chk_DataBinding"
ondatabound="chk_DataBound">
</asp:checkboxlist>
List<String> roles = new List<string>();
for (int i = 0; i < chk.Items.Count; i++)
{
if (chk.Items[i].Selected)
{
roles.Add(chk.Items[i].Value);
}
}
Your logic is consistent with the basic CheckBoxList given on the ListControl.Items page, and from personal experience, checking the .Selected property of the ListItem should work fine.
Check to make sure you aren't re-populating the CheckBoxList before you hit the "if checked" logic - if I had to guess, I'd say there's a good chance you're losing the list on every postback. The simple solution is don't call your databinding logic if it's a postback.
public string[] CheckboxListSelections(System.Web.UI.WebControls.CheckBoxList list)
{
ArrayList values = new ArrayList();
for(int counter = 0; counter < list.Items.Count; counter++)
{
if(list.Items[counter].Selected)
{
values.Add(list.Items[counter].Value);
}
}
return (String[]) values.ToArray( typeof( string ) );
}