ASP.NET Dropdown List in Codebehind vs in ASPX page - asp.net

I am generating a dropdown list in codebehind and cannot get the selectedindexchanged event to fire automatically. It works fine when put directly into the ASPX page, but I need it to be in the codebehind.
This doesn't work:
var deptList = new DropDownList
{
ID = "deptList",
DataSource = departments,
DataTextField = "deptname",
DataValueField = "deptid",
AutoPostBack = true,
EnableViewState = true
};
deptList.SelectedIndexChanged += new EventHandler(deptList_SelectedIndexChanged);
deptList.DataSource = departments;
deptList.DataTextField = "deptname";
deptList.DataValueField = "deptid";
if (!IsPostBack)
deptList.DataBind();
deptList.Items.Insert(0, new ListItem("---Select Department---", string.Empty));
writer.Write("Select a department: ");
deptList.RenderControl(writer);
but this works:
<asp:DropDownList ID="deptList" AutoPostBack="true" runat="server" OnSelectedIndexChanged="deptList_SelectedIndexChanged"></asp:DropDownList>

The problem may be if you are not adding the control to the page early enough. Controls need to be added early in the page lifecycle to get their events tied in.
You're probably doing it in the Load event, which is too late. Try adding it during the Init event or overriding the CreateChildControls method.
Edit: As Dave Swersky mentioned, make sure you do this on EVERY page request including postbacks.

You have a mesh in your code. Try to devide creating, data binding and events calling.
Example:
<asp:DropDownList ID="deptList" AutoPostBack="true" runat="server"></asp:DropDownList>
Then in code behind (Page_Load):
deptList.SelectedIndexChanged += new EventHandler(deptList_SelectedIndexChanged);
if (!IsPostBack)
{
deptList.DataTextField = "deptname";
deptList.DataValueField = "deptid";
deptList.DataSource = departments;
deptList.DataBind();
deptList.Items.Insert(0, new ListItem("---Select Department---", string.Empty));
}

To elaborate on Mike Mooney's answer: you also need to make sure you add the control back into the control tree on every postback. The control tree is recreated on each postback, read in from the markup. If you add it once programmatically and never again, there is no control in the tree to receive the event.

It appears that you are not adding the control to the controls collection. You must add the control somewhere in the control hierarchy and ensure it gets added on every postback to ensure the control exists to receive the event. By adding the control you shouldn't need to call RenderControl directly.

The problem i had was that if the drop down list didn't have AutoPostBack = true then it would never call the function.

Related

OnSelectedIndexChanged event occurs on one page and doesn't on another one

I guess this question is a difficult one. I have two pages with just the same functionality. First one is for People. The second one was created as a copy and then modified a little for Products.
I have DropDownLists on both pages, both DDLs have OnSelectedIndexChanged events and AutoPostBack options enabled. Both pages have code-behind procedure RefreshPage which reloads the page with id parameter. This id parameter is the actual selected value in dropdownlist.
So, by design:
1) I change DDL's selected item, it does AutoPostBack and fires OnSelectedIndexChanged event.
2) This event runs RefreshPage procedure, which adds currently selected value of the DDL to QueryString and reloads the page with it.
3) Then this ID is taken from QueryString and set to DDL. See the code.
RefreshPage successfully works on the People.aspx page. But similar procedure on the Products.aspx never runs at all. I added breakpoints into the same place of both procedures - the line with Page.Response.Redirect method. On the first page it stops and shows correct value of the parameter paramID, but the second page never reaches breakpoint. OnSelectedIndexChanged event is simply skipped.
Both pages have EnableViewState disabled. I don't use javascript or AJAX. I don't use PreRender methods.
Here is my code.
People.aspx:
<asp:DropDownList ID="ddJGroup" runat="server" OnSelectedIndexChanged="RefreshPage" AutoPostBack="True" CssClass="DropDown" Font-Bold="True"/>
People.aspx.cs:
protected void RefreshPage(object s, EventArgs e)
{
paramID = ddJGroup.SelectedValue;
Page.Response.Redirect("People.aspx?id=" + paramID);
}
Products.aspx:
<asp:DropDownList ID="ddCType" runat="server" OnSelectedIndexChanged="RefreshPage" AutoPostBack="True" CssClass="class_DropDown" Font-Bold="True"/>
In both pages I take the id parameter from QueryString and set the selected value of DropDownLists using it in the Page_Load procedure. See below.
Products.aspx.cs:
...
if ((Request.QueryString["id"] != null) && (Request.QueryString["id"] != ""))
paramID = Convert.ToInt32(Request.QueryString["id"]);
...
ddCType.DataSource = sqlReader;
ddCType.DataValueField = "c_type_id";
ddCType.DataTextField = "type_name";
ddCType.DataBind();
ddCType.SelectedIndex = ddCType.Items.IndexOf(ddCType.Items.FindByValue(Convert.ToString(paramID)));
This code works fine. But on the Products.aspx the parameter paramID never changes. It should change in the RefreshPage procedure, but the procedure never runs and never changes QueryString["id"] parameter. I mean, this page is never reloaded from RefreshPage, it just always does simple PostBack.
In the RefreshPage procedure:
protected void RefreshPage(object o, EventArgs e)
{
paramID = ddCType.SelectedValue;
Page.Response.Redirect("Products.aspx?id=" + paramID);
}
If this procedure ran, the page would reload with new id parameter and dropdownlist would get this new index.
I would Say 70-90% of the DropDownList_SelectedIndexChanged event not getting fired because of error in some Data Bindings to Controls in your page ,
check to see the Binding in your page and check if your not binding it each time the page loads check the:
if(!IsPostBack)
{
mydropdownlist.DataSource=yourDataSource;
mydropdownlist.DataBind();
}
so it won't Bind each time a postback event occur and thus the IndexChanged won't get fired
regards

How to get access to DropDownList control if I add them from code

I am trying to access a DropDownList within a div after I add them from the code-behind.
If I add DropDownList to my .aspx page like this:
<div id="FiltersDiv" runat="server">
<asp:DropDownList ID="DropDownListMenu" runat="server"
DataTextField="name" DataValueField="id"
AutoPostBack="true"
onselectedindexchanged="DropDownListMenu_SelectedIndexChanged" >
</asp:DropDownList>
I can get access in any event
protected void AddButton_Click(object sender, EventArgs e)
{
var dl = addProductLocationFiltersDiv.Controls.OfType<DropDownList>();
}
but not if I add from code
var ddl = new DropDownList();
ddl.DataSource = flist;
ddl.DataTextField = "name";
ddl.DataValueField = "id";
ddl.DataBind();
FiltersDiv.Controls.Add(ddl);
I need to add several DropDownList’s and I do not now how many will be. So, I need to looping thru.
Did I miss some attribute or how I need to do it?
When you add a control via code, you access it through the variable name.
If you need access to several of these, consider putting then in a List<DropDownList> (or List<Control> if you have different types of controls).
If you need to share these across methods in your code behind, use a field instead of a local variable.
Note, that due to how the ASP.NET page lifecycle works, you will probably need to recreate these on every postback, otherwise you will not be able to access them. The best location to recreate such controls dynamically is in the OnInit handler.
foreach(DropDownList ddl in FiltersDiv.Controls.OfType<DropDownList>())
{
Trace.Write(ddl.SelectedValue);
}
This is off the top of my head, so you may need to cast the FiltersDiv to a drop down list - As said, you'll need to make sure the controls have been recreated as soon as possible on the page before the control data is written or read.
If you try this too soon, or havn't created the controls you'll get no results.

How to specify ControlID attribute of Ajax Update Panel for dynamically created controls

If a control such as checkboxlist is created dynamically.
like this
CheckBoxList CbxList = new CheckBoxList();
CbxList.ID = "Cbx";
for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
{
CbxList.Items.Add(new ListItem(ds.Tables[0].Rows[i]["Name"]
.ToString(), ds.Tables[0].Rows[i]["ID"].ToString()));
}
ph.Controls.Add(CbxList);
If on the selectedIndexChange event of the created checkboxlist(cbx) if i am updating an ajax update panel how should i specify the ControlID Attribute. I did try Cbx in my case but it says no controls and off course that control is not created yet. So how to handle this issue
The only thing that I can think of needing a control ID is the triggers collection; if that is the case, why not put the checkboxlist within the updatepanel, and use an updatemode="always" on the panel itself?
If I understand your question, you want each checkbox to have an ID?
In that case, don't use a CheckBoxList, but use place holder instead, and add CheckBox controls to it.
However, I think the way you do it, they should get IDs such as 'Cbx_0','Cbx_1',...

Add user control after page is loaded

I am trying to add dynamically a user control I created to an aspx page after it is loaded.
I tried sending an ajax request to a handler that used RenderControl function and sent back the control's html. I appended it to the DOM using javascript.
The problem is that some of the controls must go through their Page_Load function and that doesn't happen when using RenderControl function.
Does anyone have any idea how can I do that?
try this:
System.Web.UI.Page page = new System.Web.UI.Page();
CustomUserControl userControl = page.LoadControl("~/control.ascx") as CustomUserControl;
if (userControl == null)
{
//error
}
userControl.ArticleId = id;
//call any other properties or methods you need
page.Controls.Add(userControl);
System.IO.StringWriter sw = new System.IO.StringWriter();
HttpContext.Current.Server.Execute(page, sw, false);
responseString = sw.ToString();
hope this will help!
Why dont you load and add the user control dynamically to the page?
I don't think you can do this that way.
Your controls don't go through their Page_Load, because they are not added to any control. All you are doing is rendering their html (using RenderControl) and loading it using javascript. There's no place for Page_Load event.
I would use UpdatePanel instead in that way:
<asp:UpdatePanel>
<ContentTemplate>
<asp:Panel ID="pnlDynamic" />
</ContentTemplate>
</asp:UpdatePanel>
and then in code behind add your dynamic controls to panel
pnlDynamic.Controls.Add(new YourControl());

ASP.Net - repeating input boxes on the client side using Repeater

I have the following requirement for creating a user profile in my application:
User should be able to enter multiple phone numbers/email addresses in his profile.
The screen looks somewhat like this:
- By default, on page load a single textbox for phone and email are shown.
- User can click a "+" button to add additional numbers/addresses.
- On clicking the "+" button we need to add another textbox just below the first one. User can add as many numbers/addresses as he wants. On submit, the server should collect all numbers/emails and save it in DB.
I tried using the Repeater control to do this. On page_load I bind the repeater to a "new arraylist" object of size 1. So, this renders fine - user sees a single textbox with no value in it.
When he clicks the "+" button, I ideally want to use javascript to create more textboxes with similar mark-up as the first.
My questions are these:
Can I render the new textboxes anyway using js? I notice that the HTML rendered by the repeater control is somewhat complex (names/ids) etc. and it might not be possible to correctly create those controls on client-side.
If there is a way to do #1, will the server understand that these additional inputs are items in the repeater control? Say, I want to get all the phone numbers that the user entered by iterating over Repeater.DataItems.
Conceptually, is my approach correct or is it wrong to use the Repeater for this? Would you suggest any other approach that might handle this requirement?
Coming from a Struts/JSP background, I am still struggling to get a grip on the .NET way of doing things - so any help would be appreciated.
The repeater control may be a bit of overkill for what you're trying to accomplish. It is mainly meant as a databound control for presenting rows of data.
What you can do is to dynamically create the boxes as part of the Page_Load event (C#):
TestInput.aspx :
<form id="form1" runat="server">
<asp:HiddenField ID="hdnAddInput" runat="server" />
<asp:Button ID="btnPlus" OnClientClick="setAdd()" Text="Plus" runat="server" />
<asp:PlaceHolder ID="phInputs" runat="server" />
</form>
<script type="text/javascript">
function setAdd() {
var add = document.getElementById('<%=hdnAddInput.ClientID%>');
add.value = '1';
return true;
}
</script>
TestInput.aspx.cs:
protected void Page_Load(object sender, EventArgs e)
{
if (ViewState["inputs"] == null)
ViewState["inputs"] = 1;
if (hdnAddInput.Value == "1")
{
ViewState["inputs"] = int.Parse(ViewState["inputs"].ToString()) + 1;
hdnAddInput.Value = "";
}
for (int loop = 0; loop < int.Parse(ViewState["inputs"].ToString()); loop++)
phInputs.Controls.Add(new TextBox() { ID = "phone" + loop });
}
I ended up using a PlaceHolder to dynamically add the text boxes and a HiddenField to flag when another TextBox needed to be added. Since the IDs were matching, it maintains the ViewState of the controls during each postback.
Welcome to the hairball that is dynamically-added controls in ASP.NET. It's not pretty but it can be done.
You cannot add new fields dynamically using javascript because the new field would have no representation in the server-side controls collection of the page.
Given that the requirements are that there is no limit to the number of addresses a user can add to the page, your only option is to do "traditional" dynamic ASP.NET controls. This means that you must handle the adding of the control server-side by new-ing a new object to represent the control:
private ArrayList _dynamicControls = new ArrayList();
public void Page_Init()
{
foreach (string c in _dynamicControls)
{
TextBox txtDynamicBox = new TextBox();
txtDynamicBox.ID = c;
Controls.Add(txtDynamicBox);
}
}
public void AddNewTextBox()
{
TextBox txtNewBox = new TextBox();
txtNewBox.ID = [uniqueID] // Give the textbox a unique name
Controls.Add(txtNewBox);
_dynamicControls.Add([uniqueID]);
}
You can see here that the object that backs each dynamically-added field has to be added back to the Controls collection of the Page on each postback. If you don't do this, data POSTed back from the field has nowhere to go.
If you want to user the repeater, I think the easiest way is to put the repeater in a ASP.Net AJAX update panel, add the extra textbox on the sever side.
There are definitely other way to implement this without using repeater, and it maybe much easier to add the textbox using js.
No, but you can create input elements similar to what TextBox controls would render.
No. ASP.NET protects itself from phony data posted to the server. You can't make the server code think that it created a TextBox earlier by just adding data that it would return.
The approach is wrong. You are trying to go a middle way that doesn't work. You have to go all the way in either direction. Either you make a postback and add the TextBox on the server side, or you do it completely on the client side and use the Request.Form collection to receive the data on the server side.

Resources