Solved

ViewState headache

Posted on 2010-11-09
15
447 Views
Last Modified: 2012-05-10
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!
0
Comment
Question by:nickmarshall
  • 7
  • 3
  • 2
  • +1
15 Comments
 
LVL 3

Expert Comment

by:Birdbuster
Comment Utility
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.
0
 
LVL 1

Author Comment

by:nickmarshall
Comment Utility
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!
0
 
LVL 15

Expert Comment

by:aibusinesssolutions
Comment Utility
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.
0
 
LVL 1

Author Comment

by:nickmarshall
Comment Utility
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
0
 
LVL 15

Expert Comment

by:aibusinesssolutions
Comment Utility
Have you tried sending the viewstate to the usercontrol from the default.aspx page?

Something like UserControl2.SetViewState(this.ViewState)
0
 
LVL 1

Author Comment

by:nickmarshall
Comment Utility
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.
0
Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

 
LVL 33

Expert Comment

by:Todd Gerbert
Comment Utility
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

0
 
LVL 33

Expert Comment

by:Todd Gerbert
Comment Utility
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?
0
 
LVL 1

Author Comment

by:nickmarshall
Comment Utility
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.
0
 
LVL 1

Author Comment

by:nickmarshall
Comment Utility
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.
0
 
LVL 33

Accepted Solution

by:
Todd Gerbert earned 500 total points
Comment Utility
Note that my example user control above (http:#34114901) uses the ViewState directly as a backing store for the "Text" property (i.e. setting the .Text property saves a value in the ViewState, as opposed to a private string variable), so my control behaves correctly so long as it's isntantiated any time after the ViewState has been acquired (like in Page_Load).

Also, more directly related to your questio, I was just thinking that it might make more sense for UserControl1 to raise an event when a GridView row is clicked, instead of creating UserControl2.  This way, the page can subscribe to UserControl1's event, then the page can dyncamically create UserControl2 and add it to it's List<> of controls to re-create on postback.

This would seem to me to require fewer changes to your code, make your code more re-usable, and is more logical - since the page contains both UserControl1 and UserControl2 it should be responsible for creating them, UserControl1 should not need to know or care about UserControl2 because they're siblings not parent/child.

The page:
<%@ Page Language="C#" %>

<%@ Register src="UserControl1.ascx" tagname="UserControl1" tagprefix="uc1" %>
<%@ Register Src="~/UserControl2.ascx" TagName="UserControl2" TagPrefix="uc2" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
	private static Dictionary<string, string> ControlsToReload = new Dictionary<string, string>();
	private void Page_Load(object sender, EventArgs e)
	{
		foreach (KeyValuePair<string, string> ctlDef in ControlsToReload)
		{
			Control control = LoadControl(ctlDef.Value);
			control.ID = ctlDef.Key;
			if (control is UserControl1)
				((UserControl1)control).RowSelected += uc1_RowSelected;
			DynamicallyAddedControlsPanel.Controls.Add(control);
		}
	}
	private void AddUC1_Click(object sender, EventArgs e)
	{
		UserControl1 uc1 = (UserControl1)LoadControl("~/UserControl1.ascx");
		uc1.ID = "UserControl1_1";
		uc1.RowSelected += new UserControl1.RowSelectedEventHandler(uc1_RowSelected);
		DynamicallyAddedControlsPanel.Controls.Add(uc1);
		ControlsToReload.Add(uc1.ID, "~/UserControl1.ascx");
	}

	void uc1_RowSelected(object sender, RowSelectedEventArgs e)
	{
		UserControl2 uc2 = (UserControl2)LoadControl("~/UserControl2.ascx");
		uc2.ID = "UserControl2_1";
		uc2.SelectedRowId = e.SelectedRowId;
		DynamicallyAddedControlsPanel.Controls.Add(uc2);
		ControlsToReload.Add(uc2.ID, "~/UserControl2.ascx");
	}
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
		<asp:Panel ID="DynamicallyAddedControlsPanel" runat="server"></asp:Panel>
		<hr />
		<asp:Button ID="AddUC1" Text="Add UserCtl1" runat="server" OnClick="AddUC1_Click" />
    	<br />
		<asp:Button ID="Button1" Text="Empty Postback" runat="server" />
    </div>
    </form>
</body>
</html>

Open in new window


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

public partial class UserControl1 : System.Web.UI.UserControl
{
	public delegate void RowSelectedEventHandler(object sender, RowSelectedEventArgs e);
	public event RowSelectedEventHandler RowSelected;

	protected void SimulateGridRowClickButton_Click(object sender, EventArgs e)
	{
		// I am using a button to simulate what would be the selection
		// of a row in a grid view in your actual control
		OnRowSelected(new RowSelectedEventArgs(10));
	}

	protected virtual void OnRowSelected(RowSelectedEventArgs e)
	{
		if (RowSelected != null)
			RowSelected(this, e);
	}
}

public class RowSelectedEventArgs : EventArgs
{
	public int SelectedRowId { get; set; }
	public RowSelectedEventArgs(int RowId)
	{
		this.SelectedRowId = RowId;
	}
}

Open in new window

0
 
LVL 1

Author Comment

by:nickmarshall
Comment Utility
A fantastic approach to a solution, many thanks!
0
 
LVL 1

Author Closing Comment

by:nickmarshall
Comment Utility
Fantastic!
0

Featured Post

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

More often than not, we developers are confronted with a need: a need to make some kind of magic happen via code. Whether it is for a client, for the boss, or for our own personal projects, the need must be satisfied. Most of the time, the Framework…
International Data Corporation (IDC) prognosticates that before the current the year gets over disbursing on IT framework products to be sent in cloud environs will be $37.1B.
This demo shows you how to set up the containerized NetScaler CPX with NetScaler Management and Analytics System in a non-routable Mesos/Marathon environment for use with Micro-Services applications.
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …

728 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

14 Experts available now in Live!

Get 1:1 Help Now