ASP.NET issue when removing Control on Page Load - c#

I have following Index.aspx web form:
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="Index.aspx.cs" Inherits="ProblematicWebApplication.Index" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<asp:Label ID="dummyLabel" runat="server" Text="This is dummy label." />
<form id="form1" runat="server">
<div>
<asp:DropDownList ID="intDropDownList" runat="server"/>
<br />
<asp:Button Text="Submit" OnClick="OnSubmitClicked" runat="server"/>
<br />
Selected value: <asp:Label ID="selectedValueLabel" runat="server" />
</div>
</form>
</body>
</html>
And following code behind Index.aspx.cs file:
using System;
using System.Linq;
namespace ProblematicWebApplication
{
public partial class Index : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!this.IsPostBack)
{
this.intDropDownList.DataSource = Enumerable.Range(0, 11).ToArray();
this.intDropDownList.DataBind();
}
if (this.Request["remove-dummy"] != null)
this.Controls.Remove(this.dummyLabel);
}
protected void OnSubmitClicked(object sender, EventArgs e)
{
this.selectedValueLabel.Text = this.intDropDownList.SelectedValue;
}
}
}
When I run my application with no remove-dummy parameter in query string and select some value from intDropDownList and click Submit button, selected value is accordingly presented in selectedValueLabel.
But if I run my application with remove-dummy=1 parameter in query string, dummyLabel gets removed. Now when I select some value from intDropDownList and click Submit button, selected value is not correctly written to selectedValueLabel and all items from intDropDownList are removed.
Can someone explain it to me why this is happening?
Why removing unrelated dummyLabel control has influence on intDropDownList control?

Hmm, seems odd. I got it to work by moving your code that removes the control into the Page's PreInit event:
protected void Page_PreInit(object sender, EventArgs e)
{
if (this.Request["remove-dummy"] != null)
{
this.Controls.Remove(this.dummyLabel);
}
}

It seems that ViewState loading fails in postback after dummyLabel is removed in previous page load.
Details:
first study following articles:
TRULY Understanding ViewState - Infinities Loop
ASP.NET Page Life Cycle Overview
Following image shows important ASP.NET page events and where in between ViewState handling takes place.
So what happens when declarative Control dummyLabel is removed? Here is a process:
Page is requested for the first time with query string parameter remove-dummy=1.
In Page_Load event declarative Control dummyLabel is removed.
Before SaveStateComplete event, ViewState is saved. There is no control dummyLabel in control tree, so its ViewState won't be saved.
Submit button is clicked.
Between InitComplete and PreLoad events, ViewState gets loaded. This is where it breaks because control tree now contains dummyLabel (dummyLabel gets removed after, in Load event) and ASP.NET fails in recursively loading ViewState into Page control tree. My assumption is that ViewState and Page control tree are tightly coupled and recursive ViewState loading fails as a consequence of this tight coupling.
One more situation that backs-up this theory: if you place dummyLabel at the very end of the page, issue doesn't happen anymore, because all other controls in Page control tree that come before dummyLabel already picked correct values from ViewState (ViewState structure and Page control tree are tightly coupled). If there were more controls after dummyLabel, their ViewState loading would fail.
To resolve this issue, all declarative Controls (defined in ASPX file) that should be removed, must be removed before ViewState loading takes place - in InitComplete event or any other event before it.

Related

Can not disable ViewState

I have made a simple Web Form where I try to get rid of the ViewState. When I run it and press Go the label gets the value of whatever I put in the texbox. So far all good. But the textbox maintains the value I filled in. As far as I understand it this is done by the ViewState mechanism. What do I miss?
<%# Page Language="C#" AutoEventWireup="true" Inherits="SportsPlay.Sida1" ViewStateMode="Disabled" EnableViewState="false" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server" enableviewstate="false">
<div>
<asp:TextBox runat="server" ID="txtTest" ></asp:TextBox>
<asp:Button runat="server" ID="btnGo" Text="Go" OnCommand="btnGo_Command" />
<asp:Label runat="server" ID="lblResult"></asp:Label>
</div>
</form>
</body>
</html>
<script runat="server" language="C#">
void btnGo_Command(object sender, CommandEventArgs e)
{
lblResult.Text =txtTest.Text ;
}
</script>
Aside from the previous answer you can explicitly clear it on click TextBox1.Text = ""; Or Redirect to the same page should clear everything out.
The ViewState manages the information of the current page. It is utilized by the HTML pages by ASP.NET applications to maintain the state of the web form controls. By this you can save a lot of coding by maintaining the ViewState of the objects in your Web Form.
You do not need ViewState in the following situations:
The control is repopulated on every postback. If you ignore old data, and if you repopulate the server control each time the page is refreshed then you do not need ViewState.
When you complete a web page, review the controls in the page and consider what information is being passed in the view state and whether you really need all that information to be maintained. To optimize web page size, consider disabling view state in these cases.
The control is an input control and it changes only from user actions.
The control never changes.
By default, ViewState is enabled for all server controls. ViewState can be enabled and disabled in any of the following ways:
Control Level
Page Level
Application Level
Machine Level
To disable ViewState
To disable ViewState for a single control on a page, set the EnableViewState property of the control to false, as in the following:
<asp:DropDownList ID="DropDownList1" runat="server" EnableViewState="false" />
To disable ViewState for a page
To disable ViewState for a single page, set the EnableViewState attribute in the # Page directive to false, as in the following:
<%# Page Language="C#" EnableViewState="false" AutoEventWireup="true" CodeFile="URLRouting.aspx.cs" Inherits="URL_Rewriting" %>
To disable a page's View State, add the code below in the Page class of the page.
public void DisableViewState()
{
this.Init += new EventHandler(Page_Init);
}
private void Page_Init(object sender, System.EventArgs e)
{
this.EnableViewState = false;
}
To disable ViewState for a specific application
To disable ViewState for a specific application, use the following element in the Web.config file of the application:
<configuration>
<system.web>
<pages enableViewState="false" />
</system.web>
</configuration>
To disable ViewState for all applications on a Web server
To disable ViewState for all applications on a Web server, configure the element in the Machine.config file as follows:
<Machine.config >
<system.web>
<pages enableViewState="true" />
</system.web>
</Machine.config>

ASP.NET Webform OnClick event not firing properly

I have a Default page (initial landing page) with a bunch of asp controls and everything works great. I also have an Admin page with one asp button control (I simplified for the post). Both are wrapped in form element on a Site.Master page. The button click event does not fire on my Admin page. Here is my button event and page code/code behind:
Page code
<%# Page Title="Admin1" Language="C#" MasterPageFile="~/Site.Master"
AutoEventWireup="true" CodeBehind="Admin1.aspx.cs"
Inherits="HPRMWebClientReporting.Admin1" %>
<asp:Content runat="server" ID="AdminContent"
ContentPlaceHolderID="AdminContent">
<asp:Button ID="ButtonGo" runat="server" Text="Button" Width="111px"
OnClick="ButtonGo_Click" />
</asp:Content>
Code Behind
public partial class Admin1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
}
}
protected void ButtonGo_Click(object sender, EventArgs e)
{
this.Context.Items["Msg"] = "It worked!!!.";
Server.Transfer("MessagePage.aspx");
}
}
Here is what happens:
Goes through Page_Load of Default page
Goes through Page_Load of Site.Master page
Refreshes my site and shows the Default page
At no point does it go my click event or Page_Load of my Admin page when the button is clicked? The button click should be taking it to the MessagePage page.
This is driving me crazy. I did try turning Causes Validation to false on the button with no luck. Any ideas?
Note: Also, maybe this will help someone determine what I'm doing wrong. I changed the Page Code so it does not use the MasterPageFile Site.Master and I just wrapped the button in its own form element and it worked fine but I don't want it to work that way as I want to use the Master page.
I found something that worked although I am not entirely sure why without further research. In my Site.Master page and in the form element I mentioned in the post I pulled out the action="/" and now my controls work on Admin page as I expected them too.
<form id="Form1" action="/" method="post" runat="server">
<asp:ContentPlaceHolder ID="HomeContent" runat="server">
</asp:ContentPlaceHolder>
<asp:ContentPlaceHolder ID="ContactContent" runat="server">
</asp:ContentPlaceHolder>
<asp:ContentPlaceHolder ID="AboutContent" runat="server">
</asp:ContentPlaceHolder>
<asp:ContentPlaceHolder ID="AdminContent" runat="server">
</asp:ContentPlaceHolder>
</form>

Fragment Cache a user control in asp.net webform Masterpage

I had a Masterpage which uses as sidebar for navigation .I created a user control for that sidebar as each user will have their own set of navigation menus.
Inside my UserMenu I use Infragistic webexplorer and Iam creating each item of webexplorer using ado.net result from database dynamically.
Everything is working fine .in high bandwidth but in low bandwidth it takes 3-4 seconds for the menubar to load.causing users to wait so much on each postback.
So I tried fragment caching .but i seems not working.can you suggest me whats wrong
In masterpage I did
<div>
//this is my usercontrol
<uc1:DynamicMenuBar runat="server" id="DynamicMenuBar" />
</div>
<div id="main" class="content" >
<asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
<div class="bodybackground">
</div>
</asp:ContentPlaceHolder>
</div>
In my usercontrol .ascx
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="DynamicMenuBar.ascx.cs" Inherits="ArtWebApp.DynamicMenuBar" %>
<%# Register assembly="Infragistics35.Web.v12.1, Version=12.1.20121.2236, Culture=neutral, PublicKeyToken=7dd5c3163f2cd0cb" namespace="Infragistics.Web.UI.NavigationControls" tagprefix="ig" %>
<%# OutputCache Duration="600" VaryByParam="none" %>
<ig:WebExplorerBar ID="WebExplorerBar1" runat="server" Width="250px">
</ig:WebExplorerBar>
And in my usercontrol .ascx.cs I had done the below
public partial class DynamicMenuBar : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
loadexplorerebar(); //this function creates the groups and childs based on the database result dynamically
this.WebExplorerBar1.EnableViewState = true;
}
}
I believe Page_Load will still be called even if the uc is cached. Try checking to see if it's in the cache before calling loadexplorerebar(). It'll be null if it's not in the cache.
So try changing:
if (!IsPostBack)
to:
if (!IsPostBack && WebExplorerBar1 == null)
It seems to be the internet problem. Try using AJAX call instead of server code for menu retrieval

Creating form tag programmatically not working

I have a simple web page that contains a Literal, now I want to create a form tag in code behind.
This is an example:
if (IsPostBack)
{
Literal1.Text = "form submit";
}
else
{
Literal1.Text = "<form id='myFrom' runat='server' action='default.aspx'
method='POST'><input type='submit' value='click here'/></form>";
}
This code create the form, but when I click the submit button, it doesn't go through IsPostBack path. Why?
Note that I need it to be created and sent as an string, because I want to use it in ajax for example.
IsPostBack is only enabled when the POST request originates from ASP.NET's __doPostBack() function. See How to use __doPostBack() for how to create an async postback request with JavaScript.
An ASP.NET web form is already an HTML form and encompasses all of your controls. You are nesting a form within a form which is not legal HTML.
I'd suggest you replace your nested form with a simple button. In the click handler for the button, redirect to default.aspx.
As indicated by John Wu, you don't want to implement your code this way. Nested forms -- while browsers forgive them -- are just not the way to go, especially with ASP.Net WebForms. Sure, I was able to get your code to work, BUT if you need to ajaxify your page so that it works with the WebForms postback model, then it would be much better to use the UpdatePanel control (in conjunction with the ScriptManager control).
ASP.Net WebForms is predicated on only having a single Form element used on a page, as it relates to its postback model, so you'll want to work within that constraint.
Here's some code to demonstrate the use of the UpdatePanel to ajaxify a WebForm (and take advantage of PostBack):
...the .ASPX page:
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="NestedForm_Question.aspx.cs" Inherits="StackOverflowAspNetQuestionAnswers.NestedForm_Question" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ScriptManager ID="ScriptManager" runat="server" />
<asp:UpdatePanel runat="server">
<ContentTemplate>
<asp:Literal ID="Literal1" runat="server" />
<asp:Button ID="SubmitButton" Text="Submit" runat="server" />
</ContentTemplate>
</asp:UpdatePanel>
</div>
</form>
</body>
</html>
...the associated code-behind class:
public partial class NestedForm_Question : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
SubmitButton.Click += SubmitButton_Click;
}
void SubmitButton_Click(object sender, EventArgs e)
{
Literal1.Text = "form submit";
}
}
You can see that in the code-behind class, the code that would need to be written to set the value of the literal control after the Button is clicked is the same whether the page is ajaxified or not.
I've changed my code to this:
if (Context.Request.Form.HasKeys()) // instead of if(IsPostBack)
{
Literal1.Text = "isPostBack";
}
else
{
Literal1.Text = "<form id='myFrom' runat='server' action='default.aspx' method='POST'><input type='submit' name='submitbtn' value='click here'/></form>";
}
Using different examples, I didn't find any exception to this. and it works well.
Any idea about this solution?
Note that in this way at least one of our elements in the form should have the name property.

Loading dropdownlist on click of the dropdown's arrow/lazy loading of dropdown

I have a situation where on a page there are 7-8 dropdowns, which have large amount of data to be bound. I have a radiobutton list having 2 choices and on selecting any of them, the I get the data from cache and bind all the dropdowns which takes about 6-7 seconds. But, I don't use all the dropdown every time as basic functionality is based on a date range. So I was thinking , if I could load the dropdown on demand, i.e. on click of dropdown arrow, I would bind the dropdown, the it would be better and user does not have to wait for those 6-7 seconds while switching between the radiobuttonlist choices. I tried calling a JS function on dropdown's onClick and from there firing one button's event. I am getting the data populated on dropdown's click but, the dropdown gets collapsed as soon as the data is bound, and user have to click again to select from dropdownlist items.I was just wondering if anyone can give me an idea so that the dropdown wont collapse and stays after binding, or else a full idea of lazy loading of the dropdown. I have also specified some of my code from my POC.
<%# Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/ xhtml1- transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<script type="text/javascript" language="javascript">
function load() {
//debugger;
var dropdown = document.getElementById('DropDownList1');
var ln = dropdown.options.length;
if (ln == 0) {
var btn = document.getElementById('Button1');
btn.click();
}
dropdown.click();
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="true"/>
<div>
<asp:DropDownList ID="DropDownList1" runat="server" onClick="javascript:load();">
</asp:DropDownList>
<asp:Button ID="Button1" runat="server" Text="Button" onclick="Button1_Click" Style="display: noone;"/>
</div>
</form>
</body>
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
ArrayList arr = new ArrayList();
arr.Add("Item1");
arr.Add("Item2");
arr.Add("Item3");
DropDownList1.DataSource = arr;
DropDownList1.DataBind();
}
}
</html>
I would suggest that you use different javascript events to trigger this behavior. The best that I can think of is to use the onfocus and onmouseover events.
Using the onfocus event will allow your page to work for people who navigate to the drop down lists without clicking directly on the control; a person could use the keyboard and tab until focus reaches the drop down list. Alternatively (though probably not as relevant), a person might click on a <label> tag for your drop down list control. Doing so will also cause focus to be set on the drop down list.
Using the onmouseover event will allow you to populate the drop down list before the user clicks on it, preventing the necessary second click that you mentioned.
EDIT: I did some experimentation and found that you might want to use the onmousedown event instead of the onmouseover event. The advantage is that it doesn't unnecessarily load data if the user just happens to pass the mouse over the drop down list without actually clicking on it, and it does not interrupt the expansion of the drop down list, so the user only needs to click once in order to expand it. The downside is that the user may have to wait for the data, since you're waiting until the user actually clicks in order to decide to load data. Depending on how much data you have and how fast the server can retrieve the data, this wait may or may not be significant.
Below is a simple example page where I've demonstrated using these two javascript events:
<html>
<head>
<script type="text/javascript" language="javascript">
function load(ddl)
{
if(ddl.options.length == 0)
{
ddl.options[0] = new Option("Option 1", "1", false, false);
ddl.options[1] = new Option("Option 2", "2", false, false);
ddl.options[2] = new Option("Option 3", "3", false, false);
}
}
</script>
</head>
<body>
<label for="DropDownList1">Drop Down List 1:</label>
<select id="DropDownList1" onfocus="load(this);" onmouseover="load(this);">
</select>
</body>
</html>
I haven't tried running your sample code, but it looks to me like you're using javascript to trigger a button click in order to cause a postback so that you can populate the drop down list control on the server. If you're doing a postback, then you're not going to be able to avoid having the entire page or at least part of the page reload, meaning that your drop down list won't stay expanded.
Instead of causing a postback, I'd recommend using ajax to make a call to the server in order to retrieve the data, then take that data and use it to populate your drop down list in javascript.
This seems like a decent article that explains how to set something like that up: http://www.mikesdotnetting.com/Article/97/Cascading-DropDownLists-with-jQuery-and-ASP.NET
This article is describing how to implement cascading drop down lists, which doesn't sound exactly like what you're trying to do, but it's pretty close.

Categories