Dropdown in .net usercontrol not maintaining state - asp.net

This is probably something fundamental and stupid that I've missed, but the various workarounds are causing me such huge headaches that really, I need to understand the basic problem here in order to find the best solution.
I have a usercontrol which contains a drop-down list.
<asp:DropDownList ID="ddlOrderStatus" AutoPostBack="true" runat="server" CssClass="textbox">
<asp:ListItem value="8">Pending</asp:ListItem>
<asp:ListItem value="9">On Hold</asp:ListItem>
<asp:ListItem Value="11">Complete</asp:ListItem>
<asp:ListItem Value="12">Cancelled</asp:ListItem>
</asp:DropDownList>
It does nothing in its Page_Load event.
This is in turn contained in a page which, in it's Page_Load event does some databinding on some repeater controls on the page but doesn't touch the control containing the ddl. There is no ajax on the page.
The dropdownlist is - clearly - set to autopostback = true. The postback code looks like this:
Private Sub ddlOrderStatus_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles ddlOrderStatus.SelectedIndexChanged
Dim ddl As DropDownList = DirectCast(sender, DropDownList)
Dim currentsorting As String = Request.QueryString("sort")
Dim currentpaging As String = Request.QueryString("page")
Response.Redirect(String.Format("~/admin/orders/Manage/0?sort={0}&page={1}&status={2}", currentsorting, currentpaging, ddl.SelectedValue))
End Sub
So when the ddl is changed, the page actually does a double postback. I see no way to avoid this as I need to do a postback to get the value in the ddl and then another postback to get some new data from the server based on that value.
Anyway, the long and the short of it is that when you do this the dropdownlist fails to maintain its state. So you select a value, the code does the job it's supposed to - gets the selected value then posts back again returning the new expected set of data - and then on loading again the dropdownlist is back in its default form.
This is a pernicious problem for me because of that double-postback: if I try and set the value of the ddl to equal what's in the querystring I have, effecitvely, set it to that value permanently because Page_Load - where the value is set - occurs before events are processed and so the value stays unchanged. I tried moving the code which changed the selectedvalue of the ddl into Render, but it seemed that although the selected value had changed as far as the user could see, the selected value was still the default value during processing and was treated as such.
I also tried setting the selectedValue in session and then clearing it as soon as it was populated. That worked for some scenarios, but unfortunately this page also contains some javascript that can cause it to post back - and you can't set session from client-side javascript. So that idea had to go out the window.
I'm at a loss here - this apparently simple problem has eaten a whole day of my time. Can anyone either tell me why state isn't being maintained on this control and/or suggest a way I get it to show the right value after postback without turning the selection into a permanent one?
Cheers,
Matt

In your page load:
// Only set the selected order status when the page first loads, but not on postbacks.
if( !Page.IsPostback )
{
ddlOrderStatus.SelectedValue = Request.QueryString("status");
}
Footnote:
I see no way to avoid this as I need
to do a postback to get the value in
the ddl and then another postback to
get some new data from the server
based on that value.
You could do it from javascript

I'll preface this by saying that I do my ASP.NET programming in C# and use GridViews, but the following should apply to your situation regardless:
Is it necessary for you to use the query string to hold this data? If you've declared your paging and sorting controls on your ASPX page, you can access them and their values directly in your codebehind (as Greg demonstrated in the above code by not performing a FindControl call). Has the user control setup prevented you from being able to u this? Are you instantiating the user control containing this drop-down list on a page, and then trying to access the value of the drop-down list from the page's codebehind itself, rather than the user control's code behind?

Related

How do I get the selected value of a dropdownlist usercontrol located inside of the insertitemtemplate of my formview?

I'm a .NET newbie, but here is my question:
I have an application that makes use of Master Pages. I have a page that has a formview on it used to input address information. In the insertitemtemplate is a usercontrol that I am referencing. This usercontrol is a dropdownlist that lists countries. The usercontrol has public properties to get and set the selected value. The usercontrol is not databound, but static. The id of the usercontrol in the user control .ascx files is "DropDownListCountry". When I reference it on the formview in the page, the ID is "fvDropDownListCountry".
When I am executing the command to save the user input of the formview, I want to get the selected value that the user has indicated of which country they have selected. For the other input areas, which are text boxes, I am able to use the code such as:
Dim street1 As String = CType(myFrmView.FindControl("fvTextBoxStreet1"), TextBox).Text
Quite obviously, this approach doesn't work for a drop down list which is inside of the user control. I can't forexample use:
Dim country As String = TryCast(myFrmView.FindControl("fvDropDownListCountry"), DropDownList).SelectedValue
I've looked all around to try to find the answer on how to get the selected value from this user control, but being new at this, haven't found it yet. I have looked at functions to recursively examine a control for child controls, but haven't been able to make this work.
Any help would be appreciated
Where are you trying to get this value? An asp.net TextBox <input type=text /> automatically maintains state but this is not true of an asp.net DropDownList <select />
If you are attempting to access the DropDownList during PageInit, that value will not have been loaded yet as ViewState is not available. You need to either access it in PageLoad or as part of the SelectedIndexChanged event on the DropDownList.
FYI: Pretty sure that you can set the SelectedIndex or SelectedValue properties during PageInit but you cannot read that value.

Save the checked status of a CheckBox included inside an ASP ListView

I know there are similar questions about this issue (for example, here and here) but no one results helpful for my problem.
I have a ListView control showing all the users registered in the database and there is a CheckBox for each user shown if the user is approved or not, and I wanna save the changes directly when the CheckBox's Checked property changes.
I know it's not correct to add the event handler on the ListView_ItemDataBound, because after the CheckBox's AutoPostback there is not a new binding, thus the event handler get lost. On the other hand, I can't append the method directly on the ASPX file because this way I can't know which user is affected by the change (at least, I think I can't).
Any sugestion?
Thanks a lot
You have a couple of options.
It's possible that the ListView.ItemCommand event might fire. I'm not sure, though, because the documentation just specifies buttons. You might want to experiment.
The other option would be to harness the ListView.ItemCreated command. I believe that this always runs, regardless of whether the ListView is bound or not, because the item always has to be created, even if it's from ViewState. What you would do in the event handler for that event would be to attach an event handler to the CheckBox Click or CheckChanged event (I forget what the server-side name is for a CheckBox state change event).
So i ran into the same problem. i'm curious, on your page load are you checking if its a postback?
if(!Post.IsPostBack){
//normal page load
}
If you don't have that check, it will call your page load logic, in my case it was resetting the checkbox everytime with my data object.
On the aspx on the checkbox OnCheckedChanged="ckbNameOfCheckbox_CheckedChanged" AutoPostBack="true"
In the code behind
Protected Sub ckbNameOfCheckbox_CheckedChanged(sender As Object, e As EventArgs)
Dim chkBox As CheckBox = CType(sender, CheckBox)
' Gets the item that contains the CheckBox object.
Dim item As ListViewDataItem = CType(chkBox.Parent, ListViewDataItem)
NameOfTheListView.UpdateItem(item.DisplayIndex, sender.Checked)
End Sub

Repopulating a dropdown outside an updatepanel

Probably this is an ignorance of Async postbacks, so let me lob a softball out there.
I have three cascading dropdowns in an updatepanel, using these you can pick your Store->Department->Product. A fourth DDL sits outside the updatepanel, and using this you pick your competitor. Different stores match with different competitors. A gridview (also outside) then displays the join of Store->Department->Product->Competitor Price.
This works fine when you first load and if you switch to a different store that has the same competitor. But if you change the updatepanel DDLs to a store that does not share the chosen competitor and click "Display" (causing a PostBack), I get an "Invalid Postback or callback argument." If I remove the Competitor DDL and hardcode the gridview's competitor, the error goes away and I can navigate with abandon.
Why won't that fourth DDL repopulate on postback? How do I fix this problem?
The reason is that in the latter case on change of Store->Department->Product if you are rebinding the Competitior DropDownlist then ListItems will change on the server but will not be rendered to the client because it is not inside any updatepanel and thus the Competitior DropDownlist has old values in it.
when the Postback occurs ASP.Net will not understand how these old values came and will throw "Invalid Postback or Callback argument" error.
Best way to solve this will be place your dropdownlist (and gridview) inside an updatepanel.

Gridview RowUpdating event not firing

I have a Gridview with AutoGenerateColumns="False".
I am using a TemplateField to display my Edit, Update and Cancel 'buttons' in the first column of the GridView within respective ItemTemplate and EditItemTemplate fields.
Within the ItemTemplate I have an ImageButtong with a CommandName of "Edit". This works as expected and I can put a breakpoint in the RowCommand event handler to see the "Event" command name. After it has been clicked the postback places that row in edit mode. All textboxes appear as they are meant to.
At this point in time the above EditItemTemplate is displayed with two ImageButtons within it. One has it's CommandName = "Update" and the other "Cancel".
My problem lies in that the click on the Update ImageButton posts back, but neither the RowCommand nor RowUpdating events get triggered.
I have set the requisite attributes in the GridView tag. (Note, in the gridview the EnableViewState="False" - if I set it to True I get the standard
"Failed to load viewstate. The control tree..." etc. error)
One strange thing that I've noticed that makes me think it's a ViewState problem is that if I change the CommandName of the Update button to "Edit" that postback event does get captured in the RowCommand event...
Any suggestions are welcome. Thanks.
As noted by Asem and Ron, adding the CausesValidation="false" attribute to the CommandField resolved the problem.
The reason was that I had some other validation controls on the page and on the GridView update the page was firing the other validation controls, so I think its better to set a ValidationSummary property.
I had this same situation where my "Edit" button was causing other validations (albeit hidden popups) to execute behind the scene.
From reading the solutions I was looking for the standard CausesValidation="false" property to fix the issue. I was not able to locate that field because it seems as if I was using AutoGenerateEditButton="True" to add my edit buttons to the gridview.
My SOLUTION was as follow and I hope this help you save some valuable time as well.
Set AutoGenerateEditButton="False" this way you can add this field via ASP Code.
Use the code below to add the "Edit" button field to your gridView code as follow.
<asp:commandfield showeditbutton="true" causesvalidation="false" headertext="Edit"/>
If validation was the problem, you would now be able to see your Updating module firing as axpected.
Set the GridView EnableViewState property to true.
Sean,
I understand you have the answer now but for future references you would have to create an addhandler and a delegate to do what you wanted to do. I misunderstood the question at first. But here's what you would do if you chose not to use a command field.
//This is in pageload
If Not IsPostBack Then
'Create new column for Edit buttons
'Dim field As New TemplateField
Dim actionfield As New TemplateField
actionfield.HeaderText = "Action"
Dim actioncol As DataControlField = actionfield
GridView1.Columns.Insert(8, actioncol)//the eight is the column number of where you are adding the column. below you will add the button. You really don't need to add this column programmtically. I normally do though.
End If
//rowcreated
If e.Row.RowType <> DataControlRowType.footer Then
btnedit.ToolTip = "Edits the Current Record"
btnedit.ImageUrl = "\images\bttnEditMini.gif"
GridView1.Rows(i).Cells(8).Controls.Add(btnedit)
btnedit.CommandName = "view"//notice commandname. You can manipulate it.
btnedit.CommandArgument = GridView1.Rows(i).Cells(0).Text
AddHandler btnedit.Click, AddressOf btnedit_Click
end if
//then notice you must create an imageclickeventhandler delegate
Public Delegate Sub ImageClickEventHandler(ByVal sender As Object, ByVal e As ImageClickEventArgs)
Sub btnedit_Click(ByVal sender As Object, ByVal e As ImageClickEventArgs)
//whatever actions you need to take.
end sub
I removed the master page and let the page that contained the GridView inherit from Page, and it worked. Something in my inheritance stack (or something in the MS controls) didn't work the way I had it set up.
This fixed the issue for me:
If Not Master.Page.IsPostBackEventControlRegistered Then
'logic to bind data
End If
if you change the name of the command to 'update' you will have to handle the update in rowcommand which shouldn't be a problem - right?
Check out this Question I asked. It may help
Added
Something you could do is change the commandname to whatever you'd like and handle it in Rowcommand. Make the database updates/inserts manually on rowcommand.
It has been mentioned on this page in other answers that the error is caused by validation. The reason is that there are validators on the page, which quite possibly do not apply to the particular row being edited, and for whatever reason they are not being met. If you want validators to work for your currently editing row, you will not want to set CasuesValidation to false... Instead, you will want to disable any irrelevant validators except those that you care about for the purpose of editing this row.
Find the validators that are not within the edit item template of this gridview row, set them to disabled in page_load.
Let 'CausesValidation' stay true on the template command fields (by default it is true so you can just elide it.) so that anything in the row that you want to validate still gets validated.
Profit.
I also have the same problem in a Gridview with Edit,update,cancel. Edit and Cancel event get fired but never Update Event. Then finally I change the CauseValidation to false for Update linkbuttion form the Edit Template field. It surprisingly works fine.
If you using any function for retrieving(Binding) the grid view from database and calling it in page_Load() event then it may cause this issue. try to call this function in page_LoadComplete() event and it will work.

When should EnableViewState be enabled on a server control?

Is there any guideline or rule for when the view state should be enabled on a server control? And when it should not?
I was looking at this SqlDatasource example and noticed that the view state for the label control is not enabled:
<asp:Label ID="ErrorMessageLabel" EnableViewState="false" runat="server" />
Why isn't EnableViewState enabled on the label control? I know that enabling the view state carries some overhead so I would like to use it only when it is needed.
Here's a good rule of thumb: If you (1) change a property's value in the code-behind, and (2) need to know what value you set in a later postback without recalculating the value, then you need to use ViewState.
For example. In my page's markup I might have a Label control specified like this:
<asp:Label ID="TitleLabel" runat="server" Text="Update this Employee" />
Then in the Page_Load event I have this code:
If Not IsPostBack AndAlso myEmployeeObject.IsNew Then TitleLabel.Text = "Create a new Employee"
By changing the value of the Text property, I've introduced a new element into ViewState. If I get the value of the Label's Text property during any subsequent PostBack, the value will be "Create a new Employee".
Here's what I do when I set out to minimize the amount of ViewState used by my page. I enable tracing on the page. The trace output is added to the bottom of your page when its rendered in the browser. The trace output identifies every single server control on your page and includes how much ViewState (measured in bytes, I believe) each control stores. I use this information to calculate when I want to trade the overhead of ViewState for the overhead of recalculating values.
In my previous example, I would elect to recalculate the Label's Text property on every PostBack and stop storing the Text property in ViewState. This is how my updated markup would look:
<asp:Label ID="TitleLabel" runat="server" Text="Update this Employee" EnableViewState="false" />
And my updated Page_Load event:
If myEmployeeObject.IsNew Then TitleLabel.Text = "Create a new Employee"
Only time you should use viewstate is when you need to get the value of that sucker back on a postback or something. So for the label example you'd only need viewstate enabled if you had code that said something like
void Button1_Click()
{
label1.text += " more!";
}
without viewstate the postback couldn't figure out the contents of the label and you'd just get " more!" over and over with no append. try it.
Really, our the rule of thumb at my office is just turn it off at the page level and then enable it as you need it.
First understand the view state, here is a blog entry that might help.
Start developing your pages by disabling the viewstate at the page level. Most controls in asp .net 2.0 save state required for their functioning in the Control State thus disabling view state would not affect most controls.
For controls that do save data bound to them in the view state like List box, you can avoid the data from landing in the view state (which works fine for most use cases) by doing your binding on the PreInit event.
Other than that, if you don't have a third party control that needs it or so, the performance penalty you encur from using the view state far outweighs the promised preservation of state you get between postbacks.
And finally use tools that help you see the bytes going on in your page's view state. The ASP.NET View State helper and an add in into Fiddler which shows viewstate data would help you a lot in this respect.
only enableviewstate when you want to preserve the values across http requests, other than that keep it = false. also you dont have to enableviewstate to use a control.
Whenever you have a control on which the contents will be important (like a text box or drop list) you want to enable viewstate so that the content will available and update to date on a postback.
Anytype of control which outputs somewhat static text (stuff you are not getting back from the user) typically will not have viewstate enable. This minimizes the viewstate.
You need to make sure you understand the ViewState better. No blanket statement like "only enable the ViewState if you have to" will really make sense unless you do. Understand when the viewstate gets loaded/saved/dirtied.
here's one of the better articles i've seen
To be honest I can't think of any time you would want viewstate set to true for label controls. Its a quick way to make your w3wp.exe take up hoards of memory.

Resources