I can't seem to be able to disable ViewState for controls that I add to a page dynamically.
ASPX
<%# Page Language="C#" AutoEventWireup="true" CodeFile="Page1.aspx.cs" Inherits="Page1" EnableViewState="false" %>
...
<asp:PlaceHolder ID="DropDownPlaceHolder" runat="server" EnableViewState="false" />
<asp:Button ID="Submit" runat="server" OnClick="Submit_OnClick" Text="Click Me!" EnableViewState="false"/>
...
ASPX.CS
protected override void OnInit(EventArgs e)
{
DropDownList dropDown = new DropDownList();
TextBox textBox = new TextBox();
textBox.EnableViewState = false;
dropDown.Items.Add("Apple");
dropDown.Items.Add("Dell");
dropDown.Items.Add("HP");
dropDown.AutoPostBack = true;
dropDown.EnableViewState = false;
DropDownPlaceHolder.Controls.Add(dropDown);
DropDownPlaceHolder.Controls.Add(textBox);
base.OnInit(e);
}
If I can't disable ViewState on these controls, then I can never programmatically override what a user has entered/selected.
I've tried placing this code in OnInit and Page_Load, but the effect is the same in either location -- ViewState is enabled (the DropDownList maintains selected value and TextBox retains text that was entered).
So, how can I disable ViewState and keep it from populating these controls?
Thanks!
Thanks for your response.
Unfortunately, this isn't a workable solution in my situation.
I will be dynamically loading controls based upon a configuration file, and some of those controls will load child controls.
I need to be able to turn the ViewState of controls off individually, without the need to code logic for loading controls in different places (in OnInit vs. LoadComplete
method).
#This Mat
It seems the post(back) will send the selected value, even if a control has it's viewstate turned off.
Yes. The post will always send a controls selected/current value. That's a behavior of HTTP form posting and nothing to do with ASP.NET control/view state.
What you are seeing there is the ControlState which was introduced with .Net Framework 2.0. It is designed to store the absolute minimum information for a control to work, such as the selection in your DropDownList and the text in your TextBox. Properties which are only related to appearance, such as BackColor, are still persisted within the ViewState.
Unlike ViewState you can't turn ControlState off.
I can only assume this is to avoid confusion from end-users when controls do not do what they are supposed to if they disable ViewState without understanding the consequences.
It's a "feature" -- http://support.microsoft.com/?id=316813
Thanks, Microsoft!!
I tested this a bit and found it a little odd. It seems the post(back) will send the selected value, even if a control has it's viewstate turned off.
I did find a good solution around it though, is that if you handle everything after the init and load, you will reload your control after the viewstate has been processed and it will thus, reset the values.
I used the LoadComplete event, example below:
Public Sub Page_In(ByVal sender As Object, ByVal e As EventArgs) _
Handles Me.LoadComplete
Dim ddl As New DropDownList()
ddl.EnableViewState = False
ddl.Items.Add("Hello")
ddl.Items.Add("Stackoverflow")
phTest.Controls.Add(ddl)
End Sub
Hope this helps.
Related
I've found this question asked countless times, but the answers haven't worked for me:
I have an asp:Dropdownlist that is dynamically bound from an asp:Objectdatasource. A button calls a codebehind function to store the selected value. However, in the click event function the value of the dropdown is always reset to default, AFAIK due to a postback that is called before the click event handler. When debugging I've checked that ViewStateMode is enabled and EnableViewState is true. I've been stuck with this for hours now, does anyone have a clue?
ASPX markup:
<asp:DropDownList runat="server" DataSourceID="AvailableNivamalerODS" ID="AddNivamalerDDL" />
<asp:ObjectDataSource runat="server" ID="AvailableNivamalerODS" TypeName="Nivamaler.NivamalerPresenter"
SelectMethod="GetAvailableNivamalers"></asp:ObjectDataSource>
<asp:Button runat="server"
Text="Legg til"
OnClick="AddNivamalerToTjstpl"
ID="AddNivamalerBtn"
UseSubmitBehavior="False"
CssClass="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only"/>
Codebehind
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
If Not Page.IsPostBack Then
AddNivamalerDDL.DataBind()
End If
End Sub
Click event handler:
Protected Sub AddNivamalerToTjstpl(sender As Object, e As EventArgs) Handles AddNivamalerBtn.Click
Dim nivamalerId As Integer = AddNivamalerDDL.SelectedValue
'Here nivamalerId is always the default value
End Sub
Cheers!
EDIT
The replies to previous question have basically said to put the data binding in the Page_Init method or the Page_Load method after !IsPostBack, which didn't help me.
Also a disclaimer: This is a legacy project with tons more code (the relevant code is new), but I tried to snip out the relevant bits. As far as I can see the rest of the code shouldn't affect this, but I can't be certain as I am still fairly new to ASP.Net
Put your page_load code into the page_Init section. The asp lifecycle will make the dropdown list databind() be absolutely meaningless if it is in the page load section here because a Postback causes the whole page to resubmit itself to the point of page_load and since you have the if not ispostback statement, it will reload the page structure but won't run your page load code and that is where you are losing your value. Other than that the code is fine.
I solved it, and as has been pointed out, the posted code is incomplete: The dropdown is inside a JQuery-ui dialog, which makes the dropdown lose its state. I ended up with a workaround with a Javascript function which copied the selected value to a hidden field outside the dialog and using the hidden field value in the codebehind
Having an issue with an ASP.NET GridView is empty on postback that I need some help with. I think it may have something to do with the ViewState not being setup. Anyhow I originally had the code working on single user-form until I refactored code.
Now to paint the picture I have now both a master page and a base form. My master page has the place holder and on my actual user-form I have placed the GridView within the place holder bounds as follows:
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolderMainBody" Runat="Server">
<asp:GridView ID="data" runat="server" AutoGenerateColumns="false" EnableViewState="true" ...>
...
</asp:GridView>
</asp:Content>
One of fields in the GridView is an editable comments field mutli-line textbox (the rest are non editable):
<asp:TemplateField HeaderText="Comments">
<ItemTemplate>
<asp:TextBox ID="TextBoxComments" runat="server" TextMode="MultiLine" Rows="4" Columns="40" Text='<%# Bind("Comment")%>' />
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="TextBoxCommentsEdit" runat="server" TextMode="MultiLine" Rows="4" Columns="40" Text='<%# Bind("Comment")%>' />
</EditItemTemplate>
</asp:TemplateField>
I edit one of the rows and click a submit button to postback. The GridView has 10 rows to enter into however on postback there are zero rows so my saving is lost!
My base form contains the code in the OnInit event to load the submit button and thus also handles the click event.
My OnLoad event I call the base Onload which inturn calls my user form's Page_Load handler code which has one line of code namely:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
MyBase.data = Me.data
End Sub
and in the BaseForm is declared as:
Protected WithEvents data As GridView
Protected Overrides Sub OnLoad(e As EventArgs)
MyBase.OnLoad(e)
If Not Page.IsPostBack Then
...
BindData(...)
...
End If
End Sub
in this way I can also handle all GridView events in the BaseForm.
So somewhere between the master/baseform/userform/viewstate relationship my GridView data is lost on PostBack. Any ideas?
On your Page_Load, bind the data only if IsPostBack is false.
You click on submit button that submit button fire RowUpdating event and that event contain query for update database table and after executed update query call BindData() function in your code .
Three in row I think for myself answering my own question - hooray! I do not know if that makes me intelligent or dumb because I have to search for more that a day to find a solution. Perhaps I did not give out enough information or it was not clear and this is what happens when you do things for the first time and you do not have a clue what you are doing. The vital information which was maybe not implied but hinted at, which I will spell it out for anyone else that might have the same problem, is I left out mentioning in my OnInit method I call the following code:
Dim cpl As ContentPlaceHolder = Master.FindControl("ContentPlaceHolderFooter")
btnUpdate = New Button
btn.ID = "btnUpdate"
cpl.Controls.Add(btnUpdate)
I know the purest will say why did you not add the button to the footer of the grid as opposed to an additional content placeholder in the master page - well with egg on my face I didn't.
Anyhow I moved the code above to the CreateChildControls overridable method and I also required an additional call to EnsureChildControls in my OnLoad event so my OnInit method with emphasis disintegrated!##%^* Why? Well the answer was hinted at within the answer to the other question asked on this site I mentioned in my second comment to "Rajan Chauhan" that I checked out and that is apparently whenever you iterate through the collection of controls you mess with the ViewState (hey I am just re-iterating what was said in the other post I have no authority on the matter) before it gets loaded so calling Master.FindControl is a no-no inside OnInit!
However, saying all that my RowUpdated event does not fire as I am actually editing in view mode because of my ItemTemplate markup so I will stick with what I have as my btnUpdate_Click event still works as before i.e. it does some magical code that I found on some other site that checks each row one by one for change of data and then updates that particular row only. Well I can as there is only 10 rows at most so I do not overload the ViewState too much and if it is important to know I also use paging so in reality I have more than 10 rows but did not want to mention that as I thought that might add to the confusion.
I have a page with a number of controls on. Some of the control properties/values are loaded from a database. Others are eg. date combo boxes with numbers 1-31, years 1900-2012 etc. I would like to populate the combo boxes in a for loop, but I've noticed that if I do that even as early as Page_Init, all the values get entered into the viewstate. I don't want to disable viewstate on those controls since I need it to maintain the value across postbacks when they are hidden.
Effectively, I'm asking how ASP.NET determines what the default values of the control are - it doesn't put values in to the viewstate if I enter them in the markup and I was wondering if anyone knows a way to reproduce that programmatically?
test2.aspx
<%# Page Language="VB" AutoEventWireup="false" CodeFile="test2.aspx.vb" Inherits="test2" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:DropDownList ID="ddlTest" runat="server"></asp:DropDownList>
</div>
</form>
</body>
</html>
test2.aspx.vb
Partial Class test2
Inherits Page
Protected Sub Page_Init(sender As Object, e As EventArgs) Handles Me.Init
If Request("addvals") IsNot Nothing Then
For i As Integer = 0 To 1000
ddlTest.Items.Add(i)
Next
End If
End Sub
End Class
Have just found a duplicate of this - it appears that it isn't possible...
Is it possible to set asp.net control property values in code behind without adding it to viewstate?
According to this article (linked in the duplicate question) You can create the control dynamically and databind it before adding it to the controls collection. This will be good if your databound control does not use excessive item templates (i.e. if it is DropDownList and not a GridView). Another option is to disable the ViewState on the control and make sure you save the state of the hidden controls manually in the ViewState dictionary.
Values added during the Init phase are not persisted to ViewState (they are added to the ViewState StateBag, but not marked as dirty).
If you want to set default properties while ViewState is being tracked (e.g. during the Load phase or later), then set them before adding the control to the Page's control tree if you don't want them to be persisted to ViewState. E.g.
Label label1 = new Label();
label1.Text = "Some text" // Not persisted to ViewState
Page.Controls.Add(label1);
Label label2 = new Label();
Page.Controls.Add(label2);
label2.Text = "Some text" // Persisted to ViewState
I have a number of similarly structured FormViews. In an effort to avoid duplicate markup, I've created a master page that contains the FormView, and placed a ContentPlaceHolder inside the FormView. The specific databound controls - which are the only thing that change from page to page - are then on the page that uses that master page.
So I have a master page that looks something like this:
<%# master ... %>
...
<form runat=server>
...
<asp:formview runat="server" ... >
<edititemtemplate>
... Lots of common markup ...
<asp:contentplaceholder id='FormRows' runat='server' />
... Lots more common markup ...
</edititemtemplate>
</asp:formview>
...
</form>
and a page using that master page that looks something like this:
<%# page masterpagefile="Form.Master" ... %>
<asp:content contentplaceholderid="FormRows" runat="server" >
...
<p>
Field One:
<asp:textbox runat=server text='<%#Bind("Field1")%>' id='Field1' />
</p>
<p>
Field Two:
<asp:textbox runat=server text='<%#Bind("Field2")%>' id='Field2' />
</p>
...
</asp:content>
With an existing record, the FormView sees through to the databound controls (Field1, etc) and populates them with the correct data. But when inserting or updating, it doesn't see them, and they're not included in the insert or update. In the FormView_ItemInserting event, e.Values is empty; likewise in the FormView_ItemUpdating event, e.NewValues is empty.
So:
Is there a way to provoke the FormView on the master page to see through to the databound controls inside the ContentPlaceholder?
Failing that, is there a straightforward way of identifying controls that are databound with <%#Bind(...)%> so that I can add them manually to the values bag?
There are a couple of things that come to mind why this setup will not work and may lead to more code than markup.
If you have a datasource defined in the master page it will not handle the different data bound controls from each page without adding more logic to the master page to change the query etc.
All form views will be coupled together increasing the complexity of changes down the road
I would go with separate pages for each FormView reducing the complexity of code, debugging and the ability to change
Just my two cents
I think this will prove difficult, if not possible; in fact I'm surprised that the databinding works at all!
You may want to try a different method of encapsulating your FormView control.
You could try placing the FormView control in an .ascx control with a PlaceHolder where you now have the ContentPlaceHolder.
Then on each ASPX page, you could have a mirror ASCX page that contains the filler for the placeholder. You could give them the same names (Page1.aspx uses Page1.ascx) or set up a naming convention like Page1-Content.ascx, so that your FormView ascx would figure out what it's filler control is named, use Page.LoadControl() to load the control by path, and plug that content in during the Init phase.
Now, your content controls have the advantage of being able to have public properties, so you could bind to those public properties, and have the properties shuttle the data to and from the appropriate server controls in the filler .ascx file.
Unfortunately it's double the files (because of the ASPX and ASCX required for each page) but fairly work-unintensive compared to the alternative (duplicating all that code)
Of course, you haven't told us what all your common markup is, but your common markup could go into a CommonMarkupHeader.ascx and CommonMarkupFooter.ascx as well and included on each page's unique FormView.
Where do you have server form tag? May be in content place holder insted of master page, so your values not send to server page after submit
You might be able to do something like this...
Define an interface for your "data pages" that has a method signature that returns a bindable data source..
public interface IFormViewChild {
IEnumerable GetFormData();
}
Then you can have your "data pages" implement that interface...
public class ChildDataPage : Page, IDataPage {
public IEnumerable GetFormData() {
// code to return stuff here
}
}
Finally, in your masterpage's Load() event...
if (Page is IFormViewChild) {
myFormViewControl.DataSource = ((IFormViewChild)Page).GetFormData();
myFormViewControl.DataBind();
}
Please keep in mind that this is all psudo code typed directly into this web form editor.. so it's probably wrong. But it might not be :)
Here's a provisional solution - not elegant, but it works. In the code-behind for Form.Master I have something along these lines:
Private Sub FormView1_ItemInserting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.FormViewInsertEventArgs) Handles FormView1.ItemInserting
ManuallyAddValues(e.Values)
End Sub
Private Sub FormView1_ItemUpdating(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.FormViewUpdateEventArgs) Handles FormView1.ItemUpdating
ManuallyAddValues(e.NewValues)
End Sub
Private Sub ManuallyAddValues(ByRef Values As IOrderedDictionary)
For Each Field As Core.Field In FormView1.DataSourceControl.IncludedFields
If Values(Field.Name) Is Nothing Then
Dim DataboundControl As Control = FormView1.FindControl("FormRows").FindControl(Field.Name)
Values.Add(Field.Name, GetValue(DataboundControl))
End If
Next
End Sub
This isn't so elegant because
I have to know the names of all databound controls
This relies on the assumption that the ID of each control matches the fieldname
The 'GetValue' function (not included here) is a clumsy solution: it checks for various types (textbox, dropdownlist, checkbox, etc.) and gets the string value from the appropriate property (textbox.text, dropdownlist.selectedvalue, checkbox.checked, etc.).
I'd still love to at least have a way of knowing what's bound with the '<%#Bind("Foo")%>' syntax and getting that information directly.
I have a page that uses a master page, several RequiredFieldValidators, and the Web Toolkit autocomplete extender. The following code only shows the bare minimum of the page:
<%# Page Language="C#"
AutoEventWireup="true"
CodeFile="Login.aspx.cs"
MasterPageFile="~/master.master"
Inherits="Login" %>
<asp:Content id="Content1"
contentplaceholderid="ContentPlaceHolder1"
runat="server">
<asp:UpdatePanel ID="pnlUpdate" runat="server">
<ContentTemplate>
<div>
<asp:ImageButton class="submitButton"
imageurl="images/button_submit.gif"
id="btnSubmit"
runat="server"
onclick="btnSubmit_ServerClick"/>
</div>
</ContentTemplate>
</asp:UpdatePanel>
</asp:Content>
Code-behind:
protected void btnSubmit_ServerClick
(object sender, ImageClickEventArgs e)
{
//breakpoint here does not get hit
}
The <form runat="server"> tag is in the master page. The code above does not fire the onclick event. If I get rid of the master page and add a form tag to the page, it works. Is the form tag in the master page not supported, or is this supposed to work somehow?
alt text http://digitalcopy.warnerbros.com/images/mainmenu.gif?provider=00079&disc=03403AAA-1D20-47F2-91FA-5EE632832659
You can also check if your ImageButton does not trigger validation. If it does set its CausesValidation property to false (of course if it makes sense).
I had a similar issue (different scenario). I used Page.RegisterRequiresRaiseEvent(ImageButton) and my onclick event started to fire. Why I needed to do that? I don't know.
My solution was to set the ImageButton's CausesValidation to false.
I have a similar issue with the image button and found the root cause. You are using
"ib.ID = i + ":" + j;"
as the ID of the ImageButton, the ":" is illegal name to use, as you are creating it programmatically, ASP.NET allows it to be created.
At runtime, if you look at the HTML source of the page, you will see the special characters are either ignored or replaced with "_". So the page is unable to find the correct control, thus the event won't fire. Try changing the name with plain text, the event will fire.
ib.ID = i + ":" + j;
should be changed to
ib.ID = i.toString()+":"+j.toString();
If it still doesn't work try making use of the StringBuilder to buildup the ID and assign it later to ib.ID property
This is solution that worked for me
If you are binding through data bound controls then use OnCommand attr instead of OnClick attr
You have to have the control in a form runat=server somewhere, it can be in the Master page or the .aspx file. Double check that the master page form tag is runat=server
AutoEventWireup is the property that allows the syntax you are using. Double check the setting in the Master Page, WebForm and it can also be set in the web.config.
if that doesnt work, you can always explicilty code it (which I prefer)
<script runat=server>
protected override void OnInit(EventArgs e)
{
btnSubmit.Click += delegate(object sender, EventArgs e1)
{
};
base.OnInit(e);
}
</script>
UpdatePanel can mess with server side events being raised also, so try it without the UpdatePanel. And I am sure you have a ScriptManager in the Master Page
From the code you supplied, you seem to be missing the <asp:scriptmanager> from your page. You must do one of the following:
Have the <asp:scriptmanagerproxy> on the page and the <asp:scriptmanager> on the master page.
Have <asp:scriptmanager> on your page and no <asp:scriptmanager> on the master page.
Personally, I recommend having the <form> tag on the master page, but that's personal preference.
You can always try taking out the UpdatePanel and seeing if it works. I usually start without the UpdatePanel, get everything working the way I want and then add in the UpdatePanel and debug anything that causes.
The form in the MasterPage works for me so the ScriptManager/ScriptManagerProxy mentioned by #Keltex might be an issue, though I forget them sometimes and usually get away with it.
With the UpdatePanel the button's click event will be handled via Javascript, so you might grab FireBug or equivalent (depending on browser) and follow through what actually is happening. Is it tripping on the validation and you don't see it? Is there a JS error somewhere (the Control Toolkit isn't perfect always)? Is the page actually posting back at all and just not hitting the event handler?
On my webpage i am creating imagebuttons dynamically inside a table that is contained by an updatepanel. The buttons are created by this code:
for (int i = 0; i < 15; i++)
{
TableRow tr = new TableRow();
for (int j = 0; j < 20; j++)
{
TableCell tc = new TableCell();
ImageButton ib = new ImageButton();
ib.Click += new ImageClickEventHandler(ImageButton1_Click);
ib.ImageUrl = "../img/defaultCell.jpg";
ib.ID = i + ":" + j;
tc.Controls.Add(ib);
tc.Width = 25;
tc.Height = 25;
tr.Cells.Add(tc);
}
GameTable.Rows.Add(tr);
}
}
The image buttons will not trigger click events. HOWEVER, if the line 'ib.ID = ...' is commented out, they do! That single alternation seems to fix all the issues.
I have no idea why.
If anyone can explain this, and also tell me how to trigger events keeping the ability to set button id's, i'd be much thankful
I think it may have something to do with the fact your re-assigning the id's after creating & assigning the event handler?
Do you even need to assign the id's? - Surely this is done for you anyway? - True removing the 'ib.ID = i + ":" + j;'
Make sure you use OnClick rather than onClick
Your update panel could be messing with the postback. Try it without the UpdatePanel and see if that is the culprit.
I had the same problem that OnClick event of ImageButton was not firing. But the actual problem was, at form level, I had onSubmit="return false;"
I was facing the same issue, where I was dynamically creating an ImageButton and click of that event was not triggering. hence, i created the Image button in if (IsPostBack) . Now it is working fine. And even if the page gets refresh, the ImageButton will be retained.
I've just solved a similar issue where OutputCache was enabled. When changing from asp:ImageButton to asp:Button, the event is correctly fired. Probably asp:ImageButton has some bug with OutputCache.
After none of the above suggestions worked for me, I did one more try by calling the button creation in OnInit(). This fixed my issue and now the OnClick event is firing.