Fetch cached control in ASP.NET - asp.net

I am using the following in ASP.NET webcontrols :
<%# OutputCache Duration="86400" VaryByParam="none" %>
This means that the control will be null on reload if it is already added to the cache. The problem is that on some page I want to hide this control and it would be great if this could be done from the MasterPage codebehind file(where it is loaded).
I have tried this :
if (Request.AppRelativeCurrentExecutionFilePath.ToLower().EndsWith("/sites/MySite/default.aspx") || Request.AppRelativeCurrentExecutionFilePath.ToLower().EndsWith("MySite.net"))
{
if(topGames_Mini1 != null)
{
//Load control
topGames_Mini1.visible=true;
}
}
else
{
Page.LoadControl("topGames_Mini1").Visible = false;
}
It will however throw the following exception in the else :
The file '/Bradspel/sites/MySite/community/topGames_Mini1' does not
exist.

you should better place the UserControl inside a Placeholder control. Then simply hide/show the Placeholder depending on your conditions.
The Placeholder does not render any tags for itself, so there is NO overhead of outer HTML tags.
I Assume you must have registered your UserControl in your Master page. So, place the userControl now inside a PlaceHolder control.
<asp:ContentPlaceHolder ID="MainContent" runat="server"><!-- Of Master Page -->
<asp:PlaceHolder ID="place1" runat="server">
<uc1:Test ID="Test1" runat="server" /><!-- Our User Control-->
</asp:PlaceHolder>
</asp:ContentPlaceHolder>
and in Code behind::
protected void Page_Load(object sender, EventArgs e)
{
if( _Some_Condition_)
place1.Visible = true;
else
// Hide PlaceHolder and thus all controls inside it
place1.Visible = false;
}

Related

Keep a value accessible in Page.Init between postbacks in asp.net

Ok, I've already learned that in order to keep the dynamic (created) controls and their viewstate in asp.net we must (re)create them in the Page init event, so they already exist within the page's control hierarchy before the view state is loaded.
As it says in this article.
There is no problem to achieve this behaviour if the criteria to create these controls is outside the web environment, for example a database. But what should I do if what I use to decide how many dynamic controls I have to create is actually a value that is in the controls?
I try to explain it with an example, maybe it's clearer:
Let's say that we have a textbox and two buttons. In the textbox I write the number of how many dynamic controls I want to create, for example 4 checkbox. When I hit the button1 the controls should be created. No problem. Then I check some checkboxes and hit the button2 just to fire a postback. Now I should recreate the controls in the page init event, like we said before, in order to maintain the controls and their state.
And here comes the problem. Because of I'm in the init stage I have no viewstate so I'm no able to access the value in the textbox that tells me how many dynamic checkbox should I create.
I thought that storing the value in the session object would do the trick, but it doesn't. The session object is no accessible as well.
Where can I save the value that it'll be accessible from the init event too?
Thanks and sorry for the long post!
First thing - textbox value is not stored/retrieved from view state, you cannot get textbox value from viewstate.
Coming to actual problem, here is the sequence of (imp) events init -> load view state -> bind postback data -> page load. You can retrieve textbox value only after bind postback data event (which actually takes posted data and binds to the textbox control).
In init only option is to use Request.Form{"textboxid"] to get the textbox value.
You are on the right track.
If you use TextBox, you do not need another ViewState to keep track of how many controls has been created, because TextBox control has its own ViewState already.
You can use either Page_Init or Page_Load to load control back.
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs"
Inherits="WebApplication2010.WebForm1" %>
<!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>
<form id="form1" runat="server">
<div>
<asp:TextBox runat="server" ID="NumberTextBox" />
<asp:Button runat="server" ID="CreateControlButton"
OnClick="CreateControlButton_Click"
Text="Create Control" />
<br />
<asp:PlaceHolder runat="server" ID="PlaceHolder1"></asp:PlaceHolder>
</div>
</form>
</body>
</html>
using System;
using System.Web.UI;
namespace WebApplication2010
{
public partial class WebForm1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
int ids;
if (Int32.TryParse(NumberTextBox.Text, out ids))
{
for (int i = 0; i < ids; i++)
{
Control ctrl = Page.LoadControl("WebUserControl.ascx");
ctrl.ID = i.ToString();
PlaceHolder1.Controls.Add(ctrl);
}
}
}
}
protected void CreateControlButton_Click(object sender, EventArgs e)
{
}
}
}
<%# Control Language="C#" AutoEventWireup="true"
CodeBehind="WebUserControl.ascx.cs"
Inherits="WebApplication2010.WebUserControl" %>
<asp:CheckBox runat="server" ID="CheckBox1" />
<asp:Button runat="server" ID="Button1" OnClick="Button_Click"
Text="Post Back" />
<asp:Label runat="server" ID="Label1" />
<br />
using System;
namespace WebApplication2010
{
public partial class WebUserControl : System.Web.UI.UserControl
{
protected void Button_Click(object sender, EventArgs e)
{
Label1.Text = " This control was posted back.";
}
}
}
This is the common paradox with page lifecycle when you work with code behind. For example, you save the editing customerid in viewstate but controls need to bind on init to be able to read their posted values.
Best real life solution is to do what bound controls do on postback, call explicilately the LoadPostBackData on IPostBackDataHandler interface that all controls implement, after you have created them in Page Load event.
You should create an extension method for Controls and call it when needed:
control.DataBind();
control.LoadPostedData(); // extension method

Dynamically creating ASP.NET Web User Control contain AJAX Extender is throwing error "Extender controls may not be registered after PreRender"

I am trying to dynamically add a web user control that contains an AJAX collapsible panel with a Gridview inside the panel when a user clicks on a button. I am able to add a single instance of the user control but when I add additional user controls it throws the following error:
Description: An unhandled exception occurred during the execution of
the current web request. Please review the stack trace for more
information about the error and where it originated in the code.
Exception Details: System.InvalidOperationException: Extender controls
may not be registered after PreRender.
Source Error:
An unhandled exception was generated during the execution of the
current web request. Information regarding the origin and location of
the exception can be identified using the exception stack trace below.
I am new to ASP.NET Development and the method I am using to handle postbacks is to store the user controls in a list and add them again on prerender method call. I am not sure what to do or if I am handling the creation of the user controls correctly. Any advice is appreciated.
Here is the back end code:
public partial class Test : System.Web.UI.Page
{
private IList<Control> _persistedControls;
private const string PersistedControlsSessionKey = "thispage_persistedcontrols";
static int count = 1;
private IList<Control> PersistedControls()
{
if (_persistedControls == null)
{
if (Session[PersistedControlsSessionKey] == null)
Session[PersistedControlsSessionKey] = new List<Control>();
_persistedControls = Session[PersistedControlsSessionKey] as IList<Control>;
}
return _persistedControls;
}
protected void Page_Load(object sender, EventArgs e)
{
PersistedControls();
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
IList<Control> controlsToGenerate = PersistedControls();
// regenerate dynamically created controls
foreach (var control in controlsToGenerate)
{
MasterPanel.Controls.Add(control);
}
}
protected void Button1_Click(object sender, EventArgs e)
{
Control control = LoadControl("~/WebUserControl/UseCaseSetupUserControl.ascx");
control.ID = "uc" + count++.ToString();
MasterPanel.Controls.Add(control);
_persistedControls.Add(control);
MasterPanel.Controls.Add(new LiteralControl("<br />"));
_persistedControls.Add(new LiteralControl("<br />"));
}
}
Here is the ASPX Code:
<%# Page Language="C#" AutoEventWireup="true" CodeFile="Test.aspx.cs" Inherits="Test" %>
<!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>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<div>
<asp:Button ID="Button1" runat="server" Text="Button" onclick="Button1_Click" />
<br />
<asp:Panel ID="MasterPanel" runat="server">
</asp:Panel>
</div>
</form>
</body>
</html>
Create your controls as early as possible in the Page life cycle.
Since you have the PersistedControls on load, that is where you should add them to the controls collection. The best place to add controls in Init.
If you really can't do that then use Load.
If this must be done on an event, then you can add the control there for the first time, but persist it and remember to add it back on Init or Load from the next postback onwards.
If you add controls after PreRender they cannot add any of their data to the ViewState. SaveViewState occurs just before PreRender. A lot of controls rely heavily on the ViewState to function properly. The exception is simply telling you that you should add your control earlier on in the Page lifecycle.

ASP.NET Web Forms multiple views and the lifecycle of controls that are not Visible

Given a scenario where a page/control should display different views (like tabs) in different circumstances (query string argument, postback from a control, user setting retrieved from the database) I would normally put a control like MultiView or Placeholder and switch the active view index or the Visible property like this:
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm2.aspx.cs" Inherits="TestWebApplication.WebForm2" %>
<%# Register Src="SomeControl.ascx" TagName="SomeControl" TagPrefix="uc1" %>
<!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>
<form id="form1" runat="server">
<div>
<asp:PlaceHolder runat="server" ID="phControl" Visible="false">
<uc1:SomeControl ID="SomeControl1" runat="server" />
</asp:PlaceHolder>
<asp:PlaceHolder runat="server" ID="phNotControl" Visible="false">
Some other content
</asp:PlaceHolder>
</div>
</form>
</body>
</html>
And I would switch the views in a code behind depending on the logic like this:
using System;
namespace TestWebApplication
{
public partial class WebForm2 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
phControl.Visible = false;
phNotControl.Visible = true;
}
}
}
This is the control:
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="SomeControl.ascx.cs" Inherits="TestWebApplication.SomeControl" EnableViewState="false" %>
I am the control
And the code behind of the control:
using System;
namespace TestWebApplication
{
public partial class SomeControl : System.Web.UI.UserControl
{
protected void Page_Init(object sender, EventArgs e)
{
Response.Write("I am the control's Init and I am executing heavy operations <br />");
}
protected void Page_Load(object sender, EventArgs e)
{
Response.Write("I am the control's Load <br />");
}
protected void Page_PreRender(object sender, EventArgs e)
{
Response.Write("I am the control's PreRender and I am only called if the control is Visible <br />");
}
}
}
However what if the control in question has some relatively heavy work to do (calling the database) in its init and load events? They get executed even if the control is not Visible and will slow down the page. One possible solution I see is moving all the work in the PreRender method of the child control because it is not executed for controls which are not visible. However this will not work if the control accepts user input from some dynamically populated control (think of dropdownlist) because the logic that populates the dropdown with options will not be executed.
I've come up with the following solutions:
Move the heavy work in the PreRender method and wrap it in an if(!IsPostBack). Then let the ViewState hold the possible values for the dropdown and ASP.NET will restore it. The downside is that it is using ViewState and bumping up the size of the page.
Create the control dynamically with LoadControl and add it in the placeholder from code behind. This will trigger catch up events and the code that populates the dropdown can be put in the Init method where it belongs. The downside is that the layout is defined in the code behind. Looking at the markup one cannot see what controls are on the page and looking at the code behind it is not clear where the control will appear. It also makes styling and other "design" operations more difficult.
Leave it like it is. The downside is that there will be additional database queries and if there are a lot of views these would add up.
My actual question is how I solve this problem without putting stuff in the ViewState, without multiple queries and without dragging my layout into the code behind.
Could it be a solution to make an AJAX call for your heavy database work?
Then you could display the View and in the background load the data you need and display it. The page would load really fast and you could display some indication that data is currently being loaded.
How about creating a public method on in your user controls, such as InitControl(). Do all the heavy work within InitControl() instead on page load. Then, on parent page, when page is being shown, call InitControl.
using System;
namespace TestWebApplication
{
public partial class WebForm2 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
phControl.Visible = false;
phNotControl.Visible = true;
SomeControl1.InitControl();
}
}
}
Don't do any work within OnLoad event of your user controls.

Disabling Update panel from content page

Hello I have a ToolkitScriptManager and update panel on master page. I want to disable update panel functionality on a content page but it should work fine for other pages.
Master Page Code:
<ajax:ToolkitScriptManager runat="server" ID="sm1" EnableScriptGlobalization="true"
EnableScriptLocalization="true" ScriptMode="Release" CompositeScript-
ScriptMode="Release" />
<asp:UpdatePanel ID="udpEmail" runat="server">
<ContentTemplate>
<asp:ContentPlaceHolder ID="cphMain" runat="server">
</asp:ContentPlaceHolder>
</ContentTemplate>
</asp:UpdatePanel>
Content Page Code:(e.g. Page1.aspx)
<asp:Content ID="Content3" ContentPlaceHolderID="cphMain" runat="Server">
Code Here
</asp:Content>
So Now I want to that Update panel functionality should not work on Page1.aspx but it should work on other content pages of same master page. Please help
what about on the code behind to check for the name of the page and set the visibility of cphMain to false? http://forums.asp.net/t/1163743.aspx
Have you explored Razor + MVC yet?
On the page where it should be disabled, try something like this:
UpdatePanel panel = Page.Form.FindControl("UpdatePanel1") as UpdatePanel;
if (panel != null)
{
panel.Enabled = false;
}
Depending on where the UpdatePanel is located in the master page, you may need to search the page recursively, like this:
private void DisableControl(Control parentCtrl, string controlID)
{
foreach (Control ctrl in parentCtrl.Controls)
{
if (ctrl.ID == controlID)
{
((WebControl)ctrl).Enabled = false;
continue;
}
DisableControl(ctrl, controlID);
}
}
You can either cast Master property on content page to correct masterpage type, or use
<%# MasterType %>
to have typed master page.
Then you will have access to controls on it and can disable update panel.
I haven't found a way yet better than the below, To override the onInit and add that code
protected override void OnInit(EventArgs e)
{
//disables the ajax effect, and allows postback
ScriptManager.GetCurrent(Page).EnablePartialRendering = false;
base.OnInit(e);
}

ASP.NET page with base class with dynamic master page not firing events

I am feeling that I have terribly wrong somewhere. I was working on a small asp.net app. I have some dynamic themes in the \theme folder and have implemented a page base class to load the master page on the fly. The master is having the ContentPlaceHolder like:
<asp:ContentPlaceHolder ID="cphBody" runat="server" />
Now I am adding pages that are derived from my base class and added the form elements. I know, Visual Studio has problem showing the page in the design mode. I have a dropdown box and wish to add the event of onselectedindexchange. But it is not working. the page is like this:
<%# Page Language="C#" AutoEventWireup="true" Inherits="trigon.web.Pages.MIS.JobStatus" Title="Job Status" AspCompat="true" CodeBehind="JobStatus.aspx.cs" %>
<asp:Content ID="Content1" ContentPlaceHolderID="cphBody" runat="Server">
<div id="divError" runat="server" />
<asp:DropDownList runat="server" id="jobType" onselectedindexchange="On_jobTypeSelection_Change"></asp:DropDownList>
</asp:Content>
I have also tried adding the event on the code behind like:
protected void Page_Load(object sender, EventArgs e)
{
jobType.SelectedIndexChanged += new System.EventHandler(this.On_jobTypeSelection_Change);
if (!IsPostBack)
{
JobStatus_DA da = new JobStatus_DA();
jobType.DataSource = da.getJobTypes();
jobType.DataBind();
}
}
protected void On_jobTypeSelection_Change(Object sender, EventArgs e)
{
//do something here
}
Can anybody help?
Regards,
set AutoPostBack="true" on your dropdown

Resources