Viewstate issue when dynamically adding controls in ASP.net - c#

Markup looks like this:
<form id="form1" runat="server">
<asp:TextBox ID="txt1" runat="server"></asp:TextBox>
<asp:Button ID="Button1" runat="server" Text="Do Something" />
</form>
Code behind looks like this:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
txt1.Visible = false;
Form.Controls.AddAt(0, new TextBox() { ID = "blah", Text = "blah", EnableViewState = true });
}
The problem is that when I click on the button, txt1 becomes visible again, even though I had set it's visibility to hidden. Viewstate should have retained it's visibility to hidden but for some reason does not.
Important: This only happens when I dynamically add a control using Form.Controls.AddAt. Doing so seems to mess up the viewstate for all controls after the dynamically added control.
Any ideas why? Or how to use AddAt without messing up the viewstate for all subsequent controls on the page?

Like Stilgar said, add the control in Init() instead.
The issue is that ViewState is loaded according to controls' indices between Init() and Load(), and you're messing with the order of the controls after that point. In other words, the ViewState mechanism thinks it needs to set the second TextBox's Visible property to false, but txt1 is the first TextBox at the time it makes that evaluation.
It used to be that ViewState was loaded by a control's ID (which was a FAR superior/more predictable approach), but the ASP.NET team flubbed things up big time in more recent versions of the framework.
See here for more info on page lifecycle and ViewState:
Last event in page that can still affect a page's viewstate

Related

ListBox implements IPostBackDataHandler but why can't it maintain its state like a TextBox when EnableViewState is set to false?

In this post, Understanding ASP.NET View State, the author says this:
It is a common misconception among developers that view state is somehow responsible for having TextBoxes, CheckBoxes, DropDownLists, and other Web controls remember their values across postback. This is not the case, as the values are identified via posted back form field values, and assigned in the LoadPostData() method for those controls that implement IPostBackDataHandler.
So, when I disable view state for a TextBox, it still persists its text value across postback, which is correct based on the description above.
However, when I disable view state for a ListBox, which also implements IPostBackDataHandler, it does not persists its state in postbacks. For example, the code provided below is supposed to add duplicate items when a button (in the same webform) is clicked (with an empty event handler), but it does not.
Am I missing something here?
protected void Page_Load(object sender, EventArgs e)
{
lbox.Items.Add("1");
lbox.Items.Add("2");
lbox.Items.Add("3");
}
I think the answer can be found from the image below. (And as tested)
As you notice in Step 1, the value in lblMessage.Text is "Hello World!", without anything to Raise PostBack Event Stage, therefore the value is retained as is.
<asp:Label runat="server" ID="lblMessage"
Font-Name="Verdana" Text="Hello, World!"></asp:Label>
<br />
<asp:Button runat="server"
Text="Change Message" ID="btnSubmit"></asp:Button>
<br />
<asp:Button runat="server" Text="Empty Postback"></asp:Button>
And the code-behind class contains the following event handler for the
Button's Click event:
private void btnSubmit_Click(object sender, EventArgs e)
{
lblMessage.Text = "Goodbye, Everyone!";
}
Next then, for textboxes EVEN if you disable the view-state to a specific control / whole page, what's saved is the PostBack Event, thats why if you take a look at Step 3, the previous PostBack is loaded as part of Load View State Stage, which makes the "Hello World!" that's been Instantiated, overwritten.
This explanation BTW only applies for control events that does not use DataSource, other controls that requires DataSource seems implicitly defined in the doc.
In the sentences you quote, the word "values" refers specifically to the form field values posted by the browser to the server when the user submits the form. These values are defined by the HTML specification:
For a TextBox control, which is rendered as an <input type="text"> element, the browser posts the text entered in the text box. The TextBox control's IPostBackDataHandler implementation reads this value and assigns it to the Text property.
For a ListBox control, which is rendered as a <select> element, the browser posts the value of each selected <option>. (The browser does not post the entire list of <option> elements.) The ListBox control's IPostBackDataHandler implementation reads these values and selects/deselects each ListItem accordingly. (The implementation does not add any items.)
The important point is that the browser posts these values regardless of whether view state is enabled or disabled. Thus, even when view state is disabled, TextBox.Text and ListBox.SelectedValue will retain the user's input across postbacks.
However, anything else not normally posted by the browser (such as the list of options in a ListBox) requires view state to be enabled for it to be preserved across postbacks.

Set focus back to the proper textbox after autopostback function (Page.SetFocus doesn't solve the issue)

Now, this MAY look a duplicate, but it's not.
Every solution on the internet shows you how to get focus on the textbox that fired the event.
But what if the user presses tab? The textbox that should have focus is the next one.
So we do a workaround and focus on the textbox that have TabIndex higher than the one that fired the event.
But then what if the user presses Shift+tab?
Even worse: what if the user clicks on another random textbox?
This is the issue.
I don't think a code is required here, because it's a general solution to set focus on textboxes that have autopostback function.
If code is required, please ask in the comments.
The following will allow you to do what you want:
What we need to do is have js assist with what control will be next, in this case any control that is getting focus (whether it be via tab, shift-tab, click, or whatever control combination leaps out of the text box and onto a different control). By utilizing a WebMethod we can pass this information onto the server for AutoPostBack focus.
WebMethod:
[WebMethod]
public static void set_nextFocus(string id)
{
_toFocus = id;
}
Simple enough, _toFocus is class variable static string _toFocus, it holds the value of the next control to focus.
Page_Load
protected void Page_Load(object sender, EventArgs e)
{
if (Page.IsPostBack)
{
//sets focus to the proper control
Page.SetFocus(Page.FindControl(_toFocus));
}
}
JavaScript
in <head>
<script type="text/javascript">
function setFocus(x) {
PageMethods.set_nextFocus(x);
}
</script>
ASP controls
In this example, a TextBox. Note the use of OnFocusIn. It is an expando attribute of the ASP control which will realize there is no server-side definition, and revert to javascript's onfocusin attribute.
<asp:TextBox ID="TextBox1" runat="server" AutoPostBack="True" TabIndex="1"
ontextchanged="TextBox1_TextChanged" OnFocusIn="setFocus(this.id)" >
</asp:TextBox>
Also, in order to use PageMethods you must enable it within the form, like so:
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="true" />
You can check the __EVENTTARGET property of form which will tell you the textbox name from which the event has been raised.
Scenario, say I have two textboxes named TextBox1 and TextBox2 for both AutoPostBack set to true and hooked up textChanged event to single handler TextBox1_TextChanged. You can have below code and set the focus back to the specific textbox control
protected void TextBox1_TextChanged(object sender, EventArgs e)
{
string target = Request.Form["__EVENTTARGET"];
if (target == "Textbox2") //conrol name should be exact
{
Page.SetFocus(this.TextBox2);
}
}

Why getting post back when I am focusing the control in its events?

In asp.net web project I have one form in which I created all controls in one update panel then all control's events are working properly but when I focusing that control in those events at last then why update panel not working? page getting post back.
created textbox control in update panel
<asp:UpdatePanel ID="UpdatePanel2" runat="server"><ContentTemplate>--%>
<asp:TextBox ID="txtUserId" runat="server" TabIndex="1" Enabled="false"
ontextchanged="txtUserId_TextChanged" AutoPostBack="true">
</asp:TextBox></ContentTemplate>
</asp:UpdatePanel>
focusing at final in its event.
protected void txtUserId_TextChanged(object sender, EventArgs e)
{
ViewState["UserIdActive"] = "true";
checkUserName();
txtUserId.Focus();
}
As per my understanding about the question , please check whether autopostback property is true or false for controls.
If its true,it postbacks.
Thank you.
As per my understanding about the question , please check whether autopostback property is true or false for controls.
If its true,it postbacks.
the events fire even if you make autopostback false.
making it true will reload the page which starts the asp.net cycle from page_load again.
so make it false and check.it fires only the required events.
Thank you.

Reading controls from previous page in asp.net

I have Page1.aspx containing
Name: <asp:TextBox ID="txt1" runat="server" />
Page2.aspx tries to access its contents by
TextBox txt2 = (TextBox)PreviousPage.FindControl("txt1");
However I end up getting an Object reference not set to instance of an object exception
I've used PreviousPage before and have had success with this snippet of code I found elsewhere online (Can't remember where I found it!)
So..
Option 1:
On your first page you have your button that takes you to the second page, you need to set the PostBackUrl property to the new page url:
<asp:Button ID="button1" Runat="server" Text="submit" PostBackUrl="~/Page2.aspx" />
(This is presuming that your 1st page is a form that redirects to your Page2.aspx)
Then in the new page's code behind you need to write something along the lines of this:
public void page_load()
{
if(!IsPostBack)
{
TextBox tb = (TextBox)PreviousPage.FindControl("txt2");
Response.Write(tb.Text);}
}
You will need to transfer the value of the previous page's txt2.Text to a textbox or label on the new page if you are wanting to do any more postbacks on the second page, otherwise you will lose that value.
Option 2:
You could also use a Session variable surely to store your data?!
Session["text"] = txt2.Text;
Once your'e in the new page, the last page is probably gone, I'd suggest transferring your data over the session.

How I can deactivate ViewState without Control problems

I wrote a ASP.NET Application and it run in IIS7 of a Server. If I open this webform in my Browser and show me the Sitecode I see this...
I have many Controls how Buttons,Labels,TextBoxes and a ListView. I try to deactivate ViewState in the web.config but if I deactivate this my Application don't run correctly. What can I do?
Deactivate only the controls that not need the viewstate.
To do that you need to understand what the viewstate is.
Viewstate is where the page save and remember the values of the controls to have them after a post back. Remember that, the viewstate is used after a post back.
So actually you have two times the same data, but only the viewstate is post back the previous data and code behind can be use that data.
So the main question is, what controls do you need to be remember what you have fill them in, or what controls need to remeber the previous state of them.
Lets see a simple Literal with EnableViewState on and off.
ViewState ON
<asp:Literal runat="server" EnableViewState="true" ID="txtLiterar">
Now if you place a text on this literal the text is also saved on viewstate and on code behind you can do that.
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
txtLiterar.Text = "Hello There";
}
}
So after the post back the Literal still have its content, and you can avoid to fill it again, because the viewstate have it and automatically fills it again.
ViewState OFF
<asp:Literal runat="server" EnableViewState="false" ID="txtLiterar">
Now if you place a text on this literal the text is not saved on view state and on code behind you add it as.
protected void Page_Load(object sender, EventArgs e)
{
txtLiterar.Text = "Hello There";
}
So the different is that you need to always fill that control with data on every post.
Where the viewstate is needed most.
The most needed part of the viewstate is when you fill a dropdown list. There you have a databind and code behind need to remember the values to place on the SelectValue the correct one.
Its also needed on GridView and other controls like that because is keep the previous page and other information's when you paging your data.
So you can close on most of your controls the viewstate - on that controls that you can fill them again on every post back, and on that controls that not need to remeber the previous state.
More to read:
How to optimize class for viewstate
Determine size of ASP.NET page's viewstate before serving page
Limiting view state information on AJAX calls

Categories

Resources