Why is my DropDownList empty on Postback? - asp.net

I've looked at answers to some similar question but I still can't seem to figure this out. I think I'm misunderstanding something about how ASP.NET works.
In the standard ASP.Net 4.0 'Create a new Account' form, I've added a DropDownList containing Roles to be selected for the new account. in the aspx page, the control looks like this:
<asp:DropDownList ID="RoleList" Width="100px" runat="server"></asp:DropDownList>
I am then populating the List in the Page_Load Event:
protected void Page_Load(object sender, EventArgs e)
{
RegisterUser.ContinueDestinationPageUrl = Request.QueryString["ReturnUrl"];
if (Page.IsPostBack)
{
return;
}
//Set the Role List Selections
DropDownList roleList = (DropDownList)RegisterUser.CreateUserStep.ContentTemplateContainer.FindControl("RoleList");
//set the role list
String[] roles = Roles.GetAllRoles();
foreach (String role in roles)
{
roleList.Items.Add(new ListItem(role, role));
}
}
I can see/select a role from the generated html. The problem arises when the 'Submit' button for creating a User is clicked:
protected void RegisterUser_CreatedUser(object sender, EventArgs e)
{
FormsAuthentication.SetAuthCookie(RegisterUser.UserName, false /* createPersistentCookie */);
string continueUrl = RegisterUser.ContinueDestinationPageUrl;
if (String.IsNullOrEmpty(continueUrl))
{
continueUrl = "~/";
}
//set user role
DropDownList roleList = (DropDownList)RegisterUser.CreateUserStep.ContentTemplateContainer.FindControl("RoleList");
Roles.AddUserToRole(RegisterUser.UserName, roleList.SelectedValue);
Response.Redirect(continueUrl);
}
Here, The roleList object contains zero items, and has no selected values. Somehow, I am losing the populating items between selection of the item, and the submit. Any idea what I'm doing wrong?

Put your dropdownlist loading into the OnInit function instead - then it should be loaded properly when RegisterUser_CreatedUser is called:
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
//Set the Role List Selections
DropDownList roleList = (DropDownList)RegisterUser.CreateUserStep.ContentTemplateContainer.FindControl("RoleList");
//set the role list
String[] roles = Roles.GetAllRoles();
foreach (String role in roles)
{
roleList.Items.Add(new ListItem(role, role));
}
}

I had a similar issue that change of radio button selection would auto postback the page and the dropdown list items would disappear after the page is back.
Solution
Check IIS -> Your WebSite -> Pages & Controls -> Enable Viewstate & Enable Sessionstate should be set to true.
Hope this helps.

The code below bypasses the proper databinding on the page load.
if (Page.IsPostBack)
{
return;
}
You need to bind this control each time so that the values are present when click events are called. You may also get event errors for operating on selected items that are no longer present.

Did you try embracing your binding with the following condition?
if (!Page.IsPostBack)
{
//Binding goes here
}

Related

asp.net - dynamically created dropdown not calling the event handler method in post back

I have a page to do a heirarchical search, it starts with a dropdownlist and based on the value selected in the dropdown it will query the database and show the childs in another dropdown list and this continues as long as it hits the leaf... so I've first dropdown added dynamically and it has the event handler on SelectedIndexChanged, when I change the selected value, it triggers the postback but however not calling event handler method.. Not sure what i'm doing wrong here.. or is it a bug??
Using a session variable to keep track the created controls
private List<DynamicControlProperties> PersistedControls
{
get
{
if (_persistedControls == null)
{
if (Session[PersistedControlsKey] == null)
{
Session[PersistedControlsKey] = new List<DynamicControlProperties>();
}
_persistedControls = Session[PersistedControlsKey] as List<DynamicControlProperties>;
}
return _persistedControls;
}
}
And in Page Init, recreating the dynamically generated controls
protected override void LoadViewState(object savedState)
{
base.LoadViewState(savedState);
// regenerate the persisted controls
foreach (var prop in PersistedControls)
{
CreateControl(prop);
}
}
In page load, created the very first dropdown
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
// create the control
CreateControl(....)
// bind the data to the dropdown
}
}
In create control method, just creating a label and a dropdown wrap it inside a and adding it to place holder
private DropDownList CreateControl(DynamicControlProperties dynamiccntrlprop)
{
// create a new HTML row
HtmlGenericControlWithParentID tr = new HtmlGenericControlWithParentID("tr");
HtmlGenericControlWithParentID td1 = new HtmlGenericControlWithParentID("td");
HtmlGenericControlWithParentID td2 = new HtmlGenericControlWithParentID("td");
// make sure we set the id and parentid
tr.ID = string.Format("tr{0}", dynamiccntrlprop.ID);
tr.ParentID = dynamiccntrlprop.ParentID;
tr.EnableViewState = true;
// create a new label for dropdown
Label lbl = new Label() { ID = string.Format("lbl{0}", dynamiccntrlprop.DisplayName), Text = dynamiccntrlprop.DisplayName };
// create a new dropdown list
DropDownList ddl = new DropDownList()
{
ID = string.Format("ddl{0}", dynamiccntrlprop.DisplayName),
// set the postback
AutoPostBack = true,
EnableViewState = true
};
// subscribe for the select index changed event
ddl.SelectedIndexChanged += new EventHandler(ddl_SelectedIndexChanged);
// add the controls to table row
td1.Controls.Add(lbl);
td2.Controls.Add(ddl);
tr.Controls.Add(td1);
tr.Controls.Add(td2);
// add the control to place holder
this.filtersPlaceHolder.Controls.Add(tr);
return ddl;
}
Here is the index changed handler,
protected void ddl_SelectedIndexChanged(object sender, EventArgs e)
{
}
Enabled the viewstate,autopostback blah blah blah... recreated the controls with same id in post back.. tried all the answers in google.. but NO luck.. It does trigger the postback when i changed the index but not calling the event handler method..
Any ideas, please???
Many Thanks,
K
You have to make sure that The CreateControl method is called on each and every page postback. This needs to happen to ensure that the dynamic control's event handler is hooked up after the postback.
protected void Page_Load(object sender, EventArgs e)
{
// you shouldn't wrap the call to CreateControl in this 'if' statement
//if (!Page.IsPostBack)
//{
// create the control
CreateControl(....)
// bind the data to the dropdown
//}
}
once you do this, the selected index changed event will fire.
Maybe It is beacuse new value of the dropdownlist don't be loaded.
protected override void LoadViewState(object savedState)
{
// regenerate the persisted controls
foreach (var prop in PersistedControls)
{
CreateControl(prop);
}
base.LoadViewState(savedState);
}

Store and transfer values in a ascx control

I have a problem that I have been struggling with for some time, and it is regarding transfering values from one control to another.
Basically I have two .ascx controls. On control1: I have an email textbox called txtEmail. The txtEmail is used to save the email in the SQL table, and on update button click, I load Control2 that has a email textbox as well. I need the emailtext box from control1 to be available on email textbox on control2.
I have tried all kinds of different ways but to no avail. I even tried using delegates and events but I can't make it work.
Does anyone know how I can do this.
Regards
Please find below the code:
public event EventHandler Notify;
public string Email
{
get { return txtEmail.Text; }
set {Email= value ; }
}
//button that will handle the update
protected void btnUpdateDB_Click(object sender, EventArgs e)
{
var email = txtEmail.Text.ToString();
public BaseClass.BAL.MBAL m = new BaseClass.BAL.MBAL();
var s = new BaseClass.Controllers.m();
s.email=email;
if(m.save(s)!=0) txtMsave.Text="Saved....";
}
//second control
public void notifyEmailChange(object sender,EventArgs e)
{
txtUsername.Text = member1.Email;
}
protected void Page_Load(object sender, EventArgs e)
{
if(Page.IsPostBack)
{
member1.Notify += new EventHandler(notifyEmailChange);
}
}
public string email {
set { txtUsers.Text = value; }}
Maybe I am trivializing the problem, but if you are wanting to be able to read/write to the text box on each of the custom controls, just make a public property that reads and writes to the textbox on each of the two controls.
public string EmailAddress {
get {
return txtEmailAddress.Text;
}
set {
txtEmailAddress.Text = value;
}
}
Now the page that contains the two controls can read the email address from the first control and write it into the email address text box in the second control.
If I am misunderstanding the problem, let me know.
The way that I have done this in the past is to have
UserControl1 have a custom event called (for instance) Notify.
The containing control wires Notify to an EventHandler
When notify fires (on the update) the consuming event handler fires and this event handler updates the email on UserControl2
Might seem overengineered but because UserControl2 can't "see" UserControl1 I think this is the way to go
Example
In UserControl1
public event EventHandler Notify;
and within the update button click event handler
if(Notify != null)
{
Notify(this, new EventArgs());
}
In parent control
in Page_Load
ucUserControl2.Notify += new EventHandler(NotifyUserControl);
and to set the message
protected void NotifyUserControl(object sender, EventArgs args)
{
ucUserControl2.Email = ucUserControl1.Email;
}
You obviously need public properties in UserControls to expose the Email text

Control caused the post back

I have a form that contains a dropdownlist,
on index changed method,i will call my user control class .cs with parameters choosen by the user, when im putting my code inside the index changed like the code below, it doesnt work, which is a normal behavior:
protected void ResourceTypesDDL_SelectedIndexChanged(object sender, EventArgs e)
{
....
MyUsercontrol c = new MyUSercontrol(....);
this.panel.controls.add(c);
}
thats why i have to put the code inside my onload method, but the thing is how can i know if it is the ddl that caused the post back? is there a propertie? or should i use page.Request.Params.Get("__EVENTTARGET") technic ?
Thanks alot !
If your MyUserControl is really user control, that means .ascx file, you should use this:
Page.LoadControl("~/Controls/MyUserControl.ascx")
instead of creating the instance of the control by calling constructor directly.
protected void ResourceTypesDDL_SelectedIndexChanged(object sender, EventArgs e) {
....
var c = Page.LoadControl("~/Controls/MyUserControl.ascx");
this.panel.controls.add(c);
}
EDIT:
But of course, after every other post back, you will lose this control. So you should also make sure that you will create all dynamic controls during OnLoad event.
set the property autoPostBack=true on the dropdownlist in order for the page to postback
Or use the below function to get the post back control on the page_load
private string GetPostBackControl()
{
string retVal = string.Empty;
try
{
string ctrlname = Page.Request.Params.Get("__EVENTTARGET");
if (ctrlname != null && ctrlname != string.Empty)
{
Control ctrl = this.Page.FindControl(ctrlname);
if (ctrl != null)
{
retVal = ctrl.ID;
}
}
}
catch (Exception ex) { ManageException(ex, ShowGeneralErrorMessage); }
return retVal;
}
Try setting AutoPostBack="True" property of drop down list. After setting this property when you select an item in list it will automatically do the postback and your event ResourceTypesDDL_SelectedIndexChanged will be fired.

Adding ImageButton Programmatically

I have a code snippet like below and I want to add imagebuttons into my asp:Panel during page load. But the events are firing already when I run the page. I want it to be fired when it is clicked.
Thanks in advance for all helps
protected void Page_Load(object sender, EventArgs e)
{...
foreach (Gift g in bonusGifts)
{
ImageButton ib = new ImageButton();
ib.ImageUrl = g.GiftBanner;
ib.ID = g.GiftID.ToString();
ib.Click += Purchase(g);
BonusGiftPanel.Controls.Add(ib);
}
}
private ImageClickEventHandler Purchase(Gift g)
{
_giftRep.Purchase(g, _userSession.CurrentUser);
lblGifts.Text = "You have purcased " + g.GiftName + " for " + g.BonusPoints;
return null;
}
Add controls in your Page_Init, not in your Page_Load. [1]
Furthermore, you are not doing this the way it should. Consider this code
//your collection of objects goes here. It might be something different than
//this, but basically a Dictionary<int, YourType> goes fine
public Dictionary<Int32, string> Ids
{
get { return (ViewState["ids"] ?? new Dictionary<Int32, string>()) as Dictionary<Int32, string>; }
set { ViewState["ids"] = new Dictionary<Int32, string>(); }
}
protected void Page_Init(object sender, EventArgs e)
{
//load the data using your DAO
Ids = new Dictionary<int, string>();
Ids.Add(1, "http://www.huddletogether.com/projects/lightbox2/images/image-2.jpg");
Ids.Add(2, "http://helios.gsfc.nasa.gov/image_euv_press.jpg");
foreach (var item in Ids)
{
ImageButton imb = new ImageButton()
{
ImageUrl = item.Value,
CommandArgument = item.Key.ToString(),
CommandName = "open"
};
imb.Click += new ImageClickEventHandler(imb_Click);
PH1.Controls.Add(imb);
}
}
void imb_Click(object sender, ImageClickEventArgs e)
{
Response.Write("You purchased " + Ids[int.Parse(((ImageButton)sender).CommandArgument)]);
}
[1] (CTRL+C/CTRL+V from some other question I answered last week):
Everything that has to be maintained between page cycles should be declared in Page_Init, not Page_Load.
All the initialization, like adding event handlers, and adding controls should be added during initialization, as the state is saved between page cycles. Handling with the content of controls and the viewstate, should be done in Load.
Check also http://msdn.microsoft.com/en-us/library/ms178472.aspx.
Init
Raised after all controls have been initialized and any skin
settings have been applied. Use this
event to read or initialize control
properties.
.
Load
The Page calls the OnLoad event method
on the Page, then recursively does the
same for each child control, which
does the same for each of its child
controls until the page and all
controls are loaded.
Use the OnLoad event method to set
properties in controls and establish
database connections.
You should add the controls in the Page Init event, as other have said.
Your image click event handler does not conform to the ImageButton Click event handler signature. That should look something like this:
private void ImageButton_Click(ByVal sender As Object, ByVal e As ImageClickEventArgs)
{
}
Note that you can't pass your "Gift" object directly to the ImageButton_Click. You will have to find another method of doing that.
You need to take a look at the Page Lifecycle - http://msdn.microsoft.com/en-us/library/ms178472.aspx

Prevent Page Refresh in C#

Duplicate of Asp.Net Button Event on refresh fires again??? GUID?
hello, ive a website and when a user click a button and the page postback, if the user refresh the Page or hit F5 the button method is called again.
any one know some method to prevent page refresh with out redirect the page to the same page again ?
something like if (page.isRefresh) or something... or if exist any javascript solution is better.
this seen to works.... but when i refresh it does not postback but show the before value in the textbox
http://www.dotnetspider.com/resources/4040-IsPageRefresh-ASP-NET.aspx
private Boolean IsPageRefresh = false;
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
ViewState["postids"] = System.Guid.NewGuid().ToString();
Session["postid"] = ViewState["postids"].ToString();
TextBox1.Text = "Hi";
}
else
{
if (ViewState["postids"].ToString() != Session["postid"].ToString())
{
IsPageRefresh = true;
}
Session["postid"] = System.Guid.NewGuid().ToString();
ViewState["postids"] = Session["postid"];
}
}
protected void Button1_Click(object sender, EventArgs e)
{
if (!IsPageRefresh) // check that page is not refreshed by browser.
{
TextBox2.Text = TextBox1.Text + "#";
}
}
Thanks for comments and sorry for my mistake,
I found this code in:
http://www.codeproject.com/KB/aspnet/Detecting_Refresh.aspx
And this time tested ;)
private bool _refreshState;
private bool _isRefresh;
protected override void LoadViewState(object savedState)
{
object[] AllStates = (object[])savedState;
base.LoadViewState(AllStates[0]);
_refreshState = bool.Parse(AllStates[1].ToString());
_isRefresh = _refreshState == bool.Parse(Session["__ISREFRESH"].ToString());
}
protected override object SaveViewState()
{
Session["__ISREFRESH"] = _refreshState;
object[] AllStates = new object[2];
AllStates[0] = base.SaveViewState();
AllStates[1] = !(_refreshState);
return AllStates;
}
protected void btn_Click(object sender, EventArgs e)
{
if (!_isRefresh)
Response.Write(DateTime.Now.Millisecond.ToString());
}
You can test for the Page.IsPostBack property to see if the page is responding to an initial request or if it's handling a PostBack such as your button click event. Here's a bit more information: w3schools on IsPostBack
Unfortunately that's not going to solve your problem since IsPostBack will be true when the user clicks the button as well as when they refresh the page after the button action has taken place.
If you're doing a task like performing CRUD on some data, you can Response.Redirect the user back to the same page when you're done processing and get around this problem. It has the side benefit of reloading your content (assuming you added a record to the DB it would now show in the page...) and prevents the refresh problem behavior. The only caveat is they still resubmit the form by going back in their history.
Postbacks were a bad implementation choice for the Asp.net and generally are what ruin the Webforms platform for me.
This doesn't solve the problem.
First of all, storing a token in the view state is not a good idea, since it can be disabled. Use control state instead. Although, a HttpModule is a better solution.
All in all, this will not work anyway. If you open another tab/window the session will be invalid for the previous tab/window. Therefore braking it. You must somehow store a unique value each time a page is first loaded. Use that to determine where the request came from and then check the "refresh ticket". As you may see, the object for one user might get pretty big depending on the amount of requests made, where and how long you store this information.
I haven't seen any solution to this I'm afraid, as it is pretty complex.
bool IsPageRefresh ;
if (Page.IsPostBack)
{
if (ViewState["postid"].ToString() != Session["postid"].ToString())
IsPageRefresh = true;
}
Session["postid"] = System.Guid.NewGuid().ToString();
ViewState["postid"] = Session["postid"];
I tried many ways and I ended up looking for the form data sent when the postback / refresh is triggered... I found that there is a Key for any VIEWSTATE created and you can just compare those Keys like...
I put that on my custom basepage to reuse it like an Property
public bool IsPageRefresh = false;
protected void Page_Init(object sender, EventArgs e)
{
if (IsPostBack)
{
var rForm = Request.Form;
var vw = rForm["__EVENTVALIDATION"].ToString();
var svw = Session["__EVENTVALIDATION"] ?? "";
if (vw.Equals(svw)) IsPageRefresh = true;
Session["__EVENTVALIDATION"] = vw;
}
}

Resources