OnSelectedIndexChanged event occurs on one page and doesn't on another one - asp.net

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

Related

Losing DropDownList items on post back

I have an webforms ASPX page, which has a dynamically added user control. The user control has two DropDownLists, one is in an UpdatePanel as its items depend on the selection in the first DropDownList.
The problem is that if you do not change the value of the first DropDownList the value of the second DropDownList does not get saved. If you do change the value of the first DropDownList then it works fine.
This is how it works briefly...
The first time the page loads, the previous values are set. This happens in the main ASPX page Page_Load event where the user control is dynamically added and the initial values are set through a property of the user control. The property sets the selected value of the first DropDownList, triggers the SelectedIndexChanged event which populates items in the second DropDownList with choices based on the first DropDownList selection, and then selects the previous value of the second DropDownList.
Then in the main ASPX page, the user control is dynamically added again on post back in the PreLoad event.
Viewstate is fully enabled throughout.
I have debugged and on post back the second DropDownList has no Items. Even during the UpdatePanel partial post back the items collection is empty. However, if the first DropDownList is changed then the Items collection is correct - it's only if the second DropDownList is last populated on the initial load that the problem happens.
Here's the relevant parts of the code...
Any help greatly appreciated.
ASPX page:
protected void Page_PreLoad(object sender, EventArgs e)
{
if (Page.IsPostBack)
{
PopulateTemplateOptions();
}
}
protected void PopulateTemplateOptions(bool init = false)
{
//this is where the control is dynamically added
//If not post back then initial values are set by passing values to
//user control's TemplateOptions property
}
User control:
public string TemplateOptions
{
set
{
//this is where the initial values are set
}
}
protected void ddlEnquirySubjectDefault_SelectedIndexChanged(object sender, EventArgs e)
{
//this is where items are added to the second drop down list based on the selection in the first one.
}
(These are the only parts that are relevant, but there's another 7,000 lines of code I didn't include.)
Here are two of my ideas:
1) This line might be wrong in your code: if (Page.IsPostBack)
It must be if (!Page.IsPostBack), although I never used Page_PreLoad event so I am not sure if it is right.
2) Try to do what you want in Page_Init event instead. I use it on my projects, without problem.

listbox selection not retaining on postback (yes i check for postback)

I have a listbox in an asp.net webpage.
I select item 2. if i have autopostback on, this reloads the page and selects item1.
I only databind the page on first load (!IsPostback), have stepped through and verified this. It's not rebinding or repopulating the list, it just selects the first item again, removing the second item selection.
Furthermore, the onselectedindexchanged event only fires AFTER postback so i cannot retain the selected index in a session variable to set on postback...
page is set to viewstateenabled, controls set to viewstateenabled, viewstatemode is enabled.
How do I set it up so that the 2nd item is still selected on postback? My code is very straightforward but I'll post it...
<asp:ListBox ID="AvailableRepairSelection" runat="server" AutoPostBack="True"
onselectedindexchanged="AvailableRepairSelection_SelectedIndexChanged"
ViewStateMode="Enabled"></asp:ListBox>
Again, I select item 2, page posts back, item1 is highlighted.
relevant parts of codebehind:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
int selectedmodel = Convert.ToInt32(Session["selectedModel"]);
List<AvailableRepair> Repairs = (from r in Database.instance().AvailableRepairs
where r.modelid == selectedmodel
select r).ToList<AvailableRepair>();
foreach (AvailableRepair repair in Repairs)
{
AvailableRepairSelection.Items.Add(new ListItem(repair.repair + ": " + repair.description + "- " + repair.cost, repair.cost));
}
}
}
PLEASE NOTE that there is more to this page but I have isolated the only issues to be with these snippets. So dont advise me how to change my page or why i am posting back a selection when theres nothing but a listbox in the page.

Getting posted-back TextBox.Text in Page_Load?

I've a asp:TextBox and a submit button on my asp.net page. Once the button was clicked, the TextBos's value is posted back. I'm going to keep the the posted-back text value into session, so that other child controls can access to the value during their Page_Load. However, I always get NOTHING ("") in the Page_Load method, and I can read the text out in the button click handler. I know that the "button click event" happens after the Page_Load. So, I'm asking how can I "pre-fetch" the TextBox.text during Page_Load?
public partial class form_staffinfo : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e){
string s = staff_id.Text; //Reach this line first, but GET empty value. However, I want to keep it in the session during this moment.
}
protected void btn_submit_Click(object sender, EventArgs e) {
string s = staff_id.Text; //Reach this line afterward, value got.
}
}
-- EDITED --
<%# Control Language="C#" AutoEventWireup="true" CodeFile="form_staffinfo.ascx.cs" Inherits="form_staffinfo" %>
<asp:Label ID="Label1" runat="server" Text="Staff ID: "></asp:Label>
<asp:TextBox ID="staff_id" runat="server" ></asp:TextBox>
<asp:Button ID="btn_submit" runat="server" Text="Query" OnClick="btn_submit_Click" />
Since I can't get the TextBox's text in the Page_Load, so, I didn't include any code related to session for clear presentation.
Thank you!
William
None of the values of your server controls are available for consumption in the Page_Load. Those controls are assigned after the form is validated (which is after the form is loaded) and before the form's control's events fire (like button clicks, in your example). The values posted are in the Request.Form Collection. Look in the AllKeys property and you should see a key that ends in $staff_id if you use your example posted. There may be other characters in from of the key, depending upon if the control is nested in a master page or other control.
If you absolutely must have that value at page load, grab it from the Request.Form collection instead of the user control, but I would question the wisdom of capturing the value that early in the page lifecycle. You could conceivably capture the textbox's OnTextChanged Event if you needed to preserve the value in Session.
EDIT - Additional Explanation
if you were going to create a custom event for your user control, there are only a couple of steps to it.
Create a delegate. This is will be the common object for inter-control messaging.
public delegate void StaffIdChangedEvent(object sender, string staffId);
Declare an event using that delegate in the user control that is going to broadcast.
public event StaffIdChangedEvent StaffIdChanged;
In your user control, when you are ready to broadcast (say from the Staff_id textbox's OnTextChanged event), you just invoke the event [Its generally a best practice to check to see if the event is null]
this.StaffIdChangedEvent(this, "staff-id-value-here");
The final step is to wire the user control event up to an event handler (this prevents the null situation I mentioned above when trying to invoke the event). You could wire a handler into the hosting page.
this.form_staffinfo.StaffIdChangedEvent += this.some_method_on_page;
Just make sure the method on the page has the same method signature as the delegate used to declare the event.
Events also could be wired into each control that needs to know about them (look up multicast delegates), so you could do something like:
this.form_staffinfo.StaffIdChangedEvent += this.some_method_on_page;
this.form_staffinfo.StaffIdChangedEvent += this.some_control_on_the_page;
this.form_staffinfo.StaffIdChangedEvent += this.some_other_control_on_the_page;
In any event, I generally preferred to do this type of wiring in the page's OnInit method.
override protected void OnInit(EventArgs e)
{
base.OnInit(e);
InitializeComponent();
}
and just write your own InitializeComponent method to centralize any of this wiring you have to do.
There is something else that is setting the textbox value. Could you please check if you are overriding other event that occurs before Page_Load and modifying the textbox text property. Even, posting the code where you update session variable would be handy. From the code you have posted, it should work.
Do you have autoeventwireup disabled? I could be mistaken, but I think if it is disabled your Page_Load will not fire. If you want to leave it disabled, you can always override the OnLoad event...
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
// do stuff
}

ASP.NET Dropdown List in Codebehind vs in ASPX page

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.

ASP.NET [Need an event after page load (After GridView renew data) ]

I renew parameters of my DataSource for GridView on Button and loads event Page_Load()
and After it (or with it) GridView renews itself.
I need to rename Header rows but there is no event after Page Load.
more information about details here :
[On Button Click] I change DataSource and Bind it (SqlDataSource1.DataBind(); ) Then sure Page gone to Refresh elements.
[On Page_Load] GridView is changing data, but if I can't change Headers there because it's looking like loads after this function :(
[one more Button] I can add new button with a function - rename headers and it works correct everytime
protected void Button2_Click(object sender, EventArgs e)
{
// Stack overflow
DataRow T;
if (go)
if (GridView2.HeaderRow.Cells.Count != 0)
for (int i = 0; i < SQF.SQF.Permission.Rows.Count; i++)
{
T = SQF.SQF.Permission.Rows[i];
GridView2.HeaderRow.Cells[i].Text = (string)T["Caption1"];
WebMsgBox.Show((string)T["Caption1"]);
}
}
Trouble : I no need one more button for it, I need to rename header rows after I click button to change Data but I have no idea where I can do it.
thank you.
Well you could use Gridview DataBound event, like that:
<asp:GridView runat="server" ID="SomeID" OnDataBound="GridVIew_OnDataBound" ... />
The DataBound event occurs right after the databinding process for that particular control has completed.
After Page_Load there is an event Page.PreRender.
Maybe it will suit you.
EDIT.
All events of your components, such as GridView, are fired between Page.Load and Page.PreRender. Consider using RowDataBound and RowUpdated events.

Resources