Stipo
Stipo

Reputation: 4606

ASP.NET issue when removing Control on Page Load

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?

Upvotes: 1

Views: 3094

Answers (2)

Stipo
Stipo

Reputation: 4606

It seems that ViewState loading fails in postback after dummyLabel is removed in previous page load.

Details:

first study following articles:

Following image shows important ASP.NET page events and where in between ViewState handling takes place.

ASP.NET Page events and ViewState handling

So what happens when declarative Control dummyLabel is removed? Here is a process:

  1. Page is requested for the first time with query string parameter remove-dummy=1.
  2. In Page_Load event declarative Control dummyLabel is removed.
  3. Before SaveStateComplete event, ViewState is saved. There is no control dummyLabel in control tree, so its ViewState won't be saved.
  4. Submit button is clicked.
  5. 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.

Upvotes: 1

Gromer
Gromer

Reputation: 9931

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);
    }
}

Upvotes: 2

Related Questions