Geeks With Blogs
Changhong's Technical Blog

 

In my last post ViewState and Dynamic Control, I mentioned that ViewStateModeByIdAttribute can be used to change the default behavior of how ASP.NET finds the controls when ViewState data restored. Now, let's have a look how it can be done.

 

For now, let's forget about ViewStateModeByIdAttribute for a second, and just have a simple page as following:

 

Default.aspx

<body>

    <form id="form1" runat="server">

        <asp:Panel ID="pnlMain" runat="Server">

        </asp:Panel>

    </form>

</body>

 

Default.aspx.cs

public partial class _Default : Page

{

    protected override void OnLoad(EventArgs e)

    {

        base.OnLoad(e);

        if (!IsPostBack)

        {

            Button button = new Button();

            button.ID = "btnClickMe";

            pnlMain.Controls.Add(button);

            button.Text = "Click me!";

        }

        else

        {

            Label label = new Label();

            label.ID = "lblMessage";

            pnlMain.Controls.Add(label);

        }

    }

}

 

Default.aspx is an extremely simple page with only one Panel on its form, in its code behind file, a new button is dynamically created and added onto the panel. On page post back, instead of recreating the button, we create a label and add it onto the panel. So, the position of the label on the control tree will be the same as the button's for the first request, and this will result in an incorrect ViewState value to be restored to label. As the result, the label will be displaying "Click me!" after a postback, though "Click me!" actually belonged to the button. (my post ViewState and Dynamic Control has more on this)

 

If we look the saved ViewState data:

 

<viewstate>

  <Pair>

    <Pair>

      <String>28670841</String>

      <Pair>

        <ArrayList>

          <Int32>3</Int32>

          <Pair>

            <ArrayList>

              <Int32>1</Int32>

              <Pair>

                <ArrayList>

                  <Int32>1</Int32>

                  <Pair>

                    <Pair>

                      <ArrayList>

                        <IndexedString>Text</IndexedString>

                        <String>Click me!</String>

                      </ArrayList>

                    </Pair>

                  </Pair>

                </ArrayList>

              </Pair>

            </ArrayList>

          </Pair>

        </ArrayList>

      </Pair>

    </Pair>

  </Pair>

</viewstate>

 

Note the part highlighted in red, it simply says: for whatever the child control with index 1 on pnlMian, the value/key pair "Click me!"/Text will be stored into its StateBag. So, on the postback, the label takes the position of index 1, and get restored with "Click me!" to its Text property.

 

Now, let's try ViewStateModeByIdAttribute. As it can be applied only on class declarations, we will not be able to use it on any existing control. We have to define a new control.

 

So, let's define a new panel with ViewStateModeById tag:

 

LoadByIdPanel.cs

[ViewStateModeById]

public class LoadByIdPanel : Panel

{

}

 

Now replace normal Panel with LoadByIdPanel in Default.aspx:

 

Default.aspx

<body>

    <form id="form1" runat="server">

        <aspx:LoadByIdPanel ID="pnlMain" runat="Server">

        </aspx:LoadByIdPanel>

    </form>

</body>

 

If we run the page now, the label will not display "Click me!". The save ViewState became:

 

<viewstate>

  <Pair>

    <Pair>

      <String>783430533</String>

      <Pair>

        <ArrayList>

          <Int32>3</Int32>

          <Pair>

            <ArrayList>

              <Int32>1</Int32>

              <Pair>

                <ArrayList>

                  <String>btnClickMe</String>

                  <Pair>

                    <Pair>

                      <ArrayList>

                        <IndexedString>Text</IndexedString>

                        <String>Click me!</String>

                      </ArrayList>

                    </Pair>

                  </Pair>

                </ArrayList>

              </Pair>

            </ArrayList>

          </Pair>

        </ArrayList>

      </Pair>

    </Pair>

  </Pair>

</viewstate>

 

Note the index now became "btnClickMe", instead of an integer value, and ASP.NET tries to find the child control with id "btnClickMe" but no control will be found on a postback, the ViewState data then will be ignored.

 

The last thing we need to be aware, ViewStateModeByIdAttribute only apply to a control's direct children. For example, if you only apply it to a page, only the form will be loaded by Id (if the form is its only child), all the controls inside the form will still be loaded by index.

Posted on Monday, February 19, 2007 10:18 PM ASP.NET | Back to top


Comments on this post: Restore ViewState data with ViewStateModeById

# re: Restore ViewState data with ViewStateModeById
Requesting Gravatar...
Can you tell me how to add LoadByIdPanel
to the *.aspx page
Left by wa on Sep 21, 2010 2:25 AM

# re: Restore ViewState data with ViewStateModeById
Requesting Gravatar...
Thanks for this, it solves the "Failed to load viewstate" error perfectly when trying to switch user controls within a placeholder...

VB version:
<ViewStateModeByIdAttribute()> _
Partial Class ........
Left by Mathieu on Nov 25, 2010 11:47 AM

Your comment:
 (will show your gravatar)


Copyright © Changhong Fu | Powered by: GeeksWithBlogs.net | Join free