Link to home
Start Free TrialLog in
Avatar of nickmarshall
nickmarshall

asked on

ViewState headache

Experts,

My web application has various UpdatePanel controls, each of which contain a PlaceHolder where dynamically loaded user controls are added during runtime.  

Currently I maintain the state using sessions, adding a List of Strings of the current view which are then loaded back during Postback.  Various user controls have buttons which when clicked will load a further user control inside one of the other PlaceHolder controls on the Page (using findcontrol from the parent to get the PlaceHolder).

I'd like to move from Sessions to ViewState, as I have achieved row clickable GridViews which I could not fix with sessions.  I have also found a number of other issues with session state management which I won't go in to here.

So, my problem is.  How can I modify the Page ViewState object from a dynamically loaded UserControl.  I'd like to do the following from the UserControl at runtime, i.e. when a user clicks a row of a GridView, store the index of the selected row:

Page parent = (Page)this.Parent;
parent.ViewState["controls"] = // New list of controls

The above doesn't work, and I understand that this is not possible (from various Microsoft articles).  I have also tried to add a public property to the Parent Page, but this is not accessible either.

Please help!
Avatar of Birdbuster
Birdbuster

So from where you trying to write you code at ? Inside the UserControl class or inside thecodebehind for the asp.net page ? It sounds like you are trying from inside the UserControl class and you want to write your code in the code behind of asp.net page.
Avatar of nickmarshall

ASKER

Let me clarify...

When a button on the main page is pressed it loads a UserControl which has a GridView control.  Managing the viewstate here is fine, however once I click on a button of the GridView to load a further "details" UserControl, which provides more information about the item clicked, I cannot access the Page ViewState to add my variable which identifies what elements are currently on screen, ie. UserControl1 (GridView) and UserControl2 (details).

Hope this makes things clearer!
Are you loading the usercontrol in the Page_Init function, or the Page_Load function?

On postback, I don't think the viewstate is available until it gets to the Page_Load function.
I am re-loading the controls in Page_Load event.  The problem is however that I can't modify the Page ViewState from a UserControl, which I must do, as all dynamically added controls are reloaded in the Page_load event of the main Page (default.aspx).  To help clarify even further I have included a graphic of the process
page.png
Have you tried sending the viewstate to the usercontrol from the default.aspx page?

Something like UserControl2.SetViewState(this.ViewState)
I'm not sure how this would help...  I don't need to read the ViewState from the UserControls, I simply need to change during runtime from the UserControls, so that on Page_Load of default.aspx, it can re-add the controls again with their settings (UserControl2 is instantiated from a GridView selection).

I've read that UserControls hold their own 'private-level' viewstate.  Should I consider adding the controls to the Page_Init event instead?

I have found very little on this subject of maintaining state with multiple usercontrols which have been added dynamically.
Avatar of Todd Gerbert
Admittedly my understanding of ViewState management is fairly limited, but since no one else has answered I'll give it a shot...
My understanding is that a custom control can add content to it's own ViewState, and the page containing the control will gather and handle the ViewState for all the controls on the page, i.e. all you need to do is use ViewState["SomeKey"] = someValue in your UserControl and ASP.Net takes care of the rest for you.
Consider this simple user control markup (code-behind is in the code block below):
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="MyControl.ascx.cs" Inherits="MyControl" %>
<asp:Label ID="ContentLabel" runat="server" Text="" />

When used in an ASPX page dynamically it behaves as expected.
protected void Page_Load(object sender, EventArgs e)
{
  MyControl myControl = (MyControl)LoadControl("~/MyControl.ascx");
  myControl.ID = "MyControl1";
  DynamicControlsPanel.Controls.Add(myControl);
}
protected void UpdateMyControl_Click(object sender, EventArgs e)
{
  ((MyControl)DynamicControlsPanel.FindControl("MyControl1")).Text = txtMyControlContent.Text;
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class MyControl : System.Web.UI.UserControl
{
	protected override void CreateChildControls()
	{
		base.CreateChildControls();

		if (ViewState["Content"] == null)
			ContentLabel.Text = "Default Value";
		else
			ContentLabel.Text = (string)ViewState["Content"];
	}
	public string Text
	{
		get
		{
			return (string)ViewState["Content"];
		}
		set
		{
			ViewState["Content"] = value;
		}
	}
}

Open in new window

Oh, I think I get it now.  What about just having UserControl1 maintain it's own List<string> of control id's that need to be created, then when Page_Load runs it'll loop through it's list and create UserControl1, and then when UserControl1 loads it can go through it's list and create UserControl2?
Hi tgerbert - Thanks for your help with this.  Your last comment may work, and it's what I was thinking of doing yesterday. I'm not sure that UserControl1's viewstate will be maintained however, because it is being added dynamically.
Just read an interesting article, http://www.4guysfromrolla.com/articles/092904-1.aspx which describes the process of adding dynamically created UserControls to the Page_Init event, which maintains the state, rather than using the Page_Load event.

I'll give this a go first.
ASKER CERTIFIED SOLUTION
Avatar of Todd Gerbert
Todd Gerbert
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
A fantastic approach to a solution, many thanks!
Fantastic!