Moving code to master page SavePageStateToPersistenceMedium & LoadPageStateFromPersistenceMedium - c#

I want to remove the view state using the method below. My problem is I don't like it put the code below into almost every page. I like to move it to the masterpage or convert it to a class and run it from the masterpage.
The code below on works on the non-masterpage .
It will have this problem if I put inside the masterpage CS0115: 'MasterPage.SavePageStateToPersistenceMedium(object)': no suitable method found to override
#region Disable ViewState
protected override void SavePageStateToPersistenceMedium(object state)
{
}
protected override object LoadPageStateFromPersistenceMedium()
{
return null;
}
#endregion

<% EnableViewState="false" %>
you can make this EnableViewState="false" on top of every page, which will disable view state on that particular page, but if you want any control to have the view state enabled than you can enable it by the same EnableViewState="true" on that control.

You should put this in a base class and have each of your pages that you don't want viewstate on inherit from it
//a basepage that overrides the methods
public class BasePage : System.Web.UI.Page
{
protected override void SavePageStateToPersistenceMedium(object state)
{
}
protected override object LoadPageStateFromPersistenceMedium()
{
return null;
}
}
//your page class that inherits your base page
public class Page1 : BasePage
{
}

Each page has an option to not use ViewState.
<asp:Page EnableViewState="True|False" />

//using the below you will need to change asp:ImageButton coding method. You need to convert it to a regular submit button. There may be other problems which i don't now yet.
Place the code below on the master page.
protected override void Render(HtmlTextWriter writer)
{///Articles/How-to-disable-or-remove-ViewState-Hidden-Field-in-ASP.Net-Page.aspx
StringBuilder sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);
HtmlTextWriter ht = new HtmlTextWriter(sw);
base.Render(ht);
string html = sb.ToString();
//The remove the value and it id from the view status this next line
html = Regex.Replace(html, "<input[^>]*id=\"(__VIEWSTATE)\"[^>]*>", "<input type=\"hidden\" name=\"__VIEWSTATE\" value=\"\"/>", RegexOptions.IgnoreCase);
//To completely remove the view state use the line below
// html = Regex.Replace(html, "<input[^>]*id=\"(__VIEWSTATE)\"[^>]*>", "", RegexOptions.IgnoreCase);
writer.Write(html);
sb = null; html = null; ht.Dispose(); sw.Dispose();
}
Use this technique to detect the clicked button on your aspx page(not the master page). Place this code in the code behind
if (Request.Form["nonPostBackButton1.y"] != null)
{
Response.Write("nonPostBackButton1 is just pressed");
}
if (Request.Form["nonPostBackButton2.y"] != null)
{
Response.Write("<br/><b>nonPostBackButton2 is just pressed</b>");
}
This is the sample of the image submit buttons
<input type="image" alt="nonPostBackButton1" name="nonPostBackButton1"/> Use this method instead of the postback buttons. This is the image submit button 1</p>
<p><input type="image" alt="nonPostBackButton2" name="nonPostBackButton2"/> Use this method instead of the postback buttons. This is the image submit button 1</p>

Related

Does a child web page inherit the text boxes which were there in the master web page? [duplicate]

I have a master page which contains a label for status messages. I need to set the status text from different .aspx pages. How can this be done from the content page?
public partial class Site : System.Web.UI.MasterPage
{
public string StatusNachricht
{
get
{
return lblStatus.Text;
}
set
{
lblStatus.Text = value;
}
}
protected void Page_Load(object sender, EventArgs e)
{
}
}
I have tried this, but was unsuccessful in making it work:
public partial class DatenAendern : System.Web.UI.Page
{
var master = Master as Site;
protected void Page_Load(object sender, EventArgs e)
{
if (master != null)
{
master.setStatusLabel("");
}
}
protected void grdBenutzer_RowCommand(object sender, GridViewCommandEventArgs e)
{
try
{
//some code
if (master != null)
{
master.setStatusLabel("Passwort erfolgreich geändert.");
}
}
catch (Exception ex)
{
if (master != null)
{
master.setStatusLabel("Passwort konnte nicht geändert werden!");
}
}
}
}
}
In the MasterPage.cs file add the property of Label like this:
public string ErrorMessage
{
get
{
return lblMessage.Text;
}
set
{
lblMessage.Text = value;
}
}
On your aspx page, just below the Page Directive add this:
<%# Page Title="" Language="C#" MasterPageFile="Master Path Name"..... %>
<%# MasterType VirtualPath="Master Path Name" %> // Add this
And in your codebehind(aspx.cs) page you can then easily access the Label Property and set its text as required. Like this:
this.Master.ErrorMessage = "Your Error Message here";
In Content page you can access the label and set the text such as
Here 'lblStatus' is the your master page label ID
Label lblMasterStatus = (Label)Master.FindControl("lblStatus");
lblMasterStatus.Text = "Meaasage from content page";
It Works
To find master page controls on Child page
Label lbl_UserName = this.Master.FindControl("lbl_UserName") as Label;
lbl_UserName.Text = txtUsr.Text;
I have a helper method for this in my System.Web.UI.Page class
protected T FindControlFromMaster<T>(string name) where T : Control
{
MasterPage master = this.Master;
while (master != null)
{
T control = master.FindControl(name) as T;
if (control != null)
return control;
master = master.Master;
}
return null;
}
then you can access using below code.
Label lblStatus = FindControlFromMaster<Label>("lblStatus");
if(lblStatus!=null)
lblStatus.Text = "something";
You cannot use var in a field, only on local variables.
But even this won't work:
Site master = Master as Site;
Because you cannot use this in a field and Master as Site is the same as this.Master as Site. So just initialize the field from Page_Init when the page is fully initialized and you can use this:
Site master = null;
protected void Page_Init(object sender, EventArgs e)
{
master = this.Master as Site;
}
This is more complicated if you have a nested MasterPage. You need to first find the content control that contains the nested MasterPage, and then find the control on your nested MasterPage from that.
Crucial bit: Master.Master.
See here: http://forums.asp.net/t/1059255.aspx?Nested+master+pages+and+Master+FindControl
Example:
'Find the content control
Dim ct As ContentPlaceHolder = Me.Master.Master.FindControl("cphMain")
'now find controls inside that content
Dim lbtnSave As LinkButton = ct.FindControl("lbtnSave")
If you are trying to access an html element: this is an HTML Anchor...
My nav bar has items that are not list items (<li>) but rather html anchors (<a>)
See below: (This is the site master)
<nav class="mdl-navigation">
<a class="mdl-navigation__link" href="" runat="server" id="liHome">Home</a>
<a class="mdl-navigation__link" href="" runat="server" id="liDashboard">Dashboard</a>
</nav>
Now in your code behind for another page, for mine, it's the login page...
On PageLoad() define this:
HtmlAnchor lblMasterStatus = (HtmlAnchor)Master.FindControl("liHome");
lblMasterStatus.Visible =false;
HtmlAnchor lblMasterStatus1 = (HtmlAnchor)Master.FindControl("liDashboard");
lblMasterStatus1.Visible = false;
Now we have accessed the site masters controls, and have made them invisible on the login page.

Get html of div in codebehind ASP.NET c# [duplicate]

<form runat="server" id="f1">
<div runat="server" id="d">
grid view:
<asp:GridView runat="server" ID="g">
</asp:GridView>
</div>
<asp:TextBox runat="server" ID="t" TextMode="MultiLine" Rows="20" Columns="50"></asp:TextBox>
</form>
Code behind:
public partial class ScriptTest : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
g.DataSource = new string[] { "a", "b", "c" };
g.DataBind();
TextWriter tw = new StringWriter();
HtmlTextWriter h = new HtmlTextWriter(tw);
d.RenderControl(h);
t.Text = tw.ToString();
}
}
Even the GridView is within a from tag with runat="server", still I am getting this error.
Any clues please ?
You are calling GridView.RenderControl(htmlTextWriter), hence the page raises an exception that a Server-Control was rendered outside of a Form.
You could avoid this execption by overriding VerifyRenderingInServerForm
public override void VerifyRenderingInServerForm(Control control)
{
/* Confirms that an HtmlForm control is rendered for the specified ASP.NET
server control at run time. */
}
See here and here.
An alternative to overriding VerifyRenderingInServerForm is to remove the grid from the controls collection while you do the render, and then add it back when you are finished before the page loads. This is helpful if you want to have some generic helper method to get grid html because you don't have to remember to add the override.
Control parent = grid.Parent;
int GridIndex = 0;
if (parent != null)
{
GridIndex = parent.Controls.IndexOf(grid);
parent.Controls.Remove(grid);
}
grid.RenderControl(hw);
if (parent != null)
{
parent.Controls.AddAt(GridIndex, grid);
}
Another alternative to avoid the override is to do this:
grid.RenderBeginTag(hw);
grid.HeaderRow.RenderControl(hw);
foreach (GridViewRow row in grid.Rows)
{
row.RenderControl(hw);
}
grid.FooterRow.RenderControl(hw);
grid.RenderEndTag(hw);
Just after your Page_Load add this:
public override void VerifyRenderingInServerForm(Control control)
{
//base.VerifyRenderingInServerForm(control);
}
Note that I don't do anything in the function.
EDIT: Tim answered the same thing. :)
You can also find the answer Here
Just want to add another way of doing this. I've seen multiple people on various related threads ask if you can use VerifyRenderingInServerForm without adding it to the parent page.
You actually can do this but it's a bit of a bodge.
First off create a new Page class which looks something like the following:
public partial class NoRenderPage : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{ }
public override void VerifyRenderingInServerForm(Control control)
{
//Allows for printing
}
public override bool EnableEventValidation
{
get { return false; }
set { /*Do nothing*/ }
}
}
Does not need to have an .ASPX associated with it.
Then in the control you wish to render you can do something like the following.
StringWriter tw = new StringWriter();
HtmlTextWriter hw = new HtmlTextWriter(tw);
var page = new NoRenderPage();
page.DesignerInitialize();
var form = new HtmlForm();
page.Controls.Add(form);
form.Controls.Add(pnl);
controlToRender.RenderControl(hw);
Now you've got your original control rendered as HTML. If you need to, add the control back into it's original position. You now have the HTML rendered, the page as normal and no changes to the page itself.
Here is My Code
protected void btnExcel_Click(object sender, ImageClickEventArgs e)
{
if (gvDetail.Rows.Count > 0)
{
System.IO.StringWriter stringWrite1 = new System.IO.StringWriter();
System.Web.UI.HtmlTextWriter htmlWrite1 = new HtmlTextWriter(stringWrite1);
gvDetail.RenderControl(htmlWrite1);
gvDetail.AllowPaging = false;
Search();
sh.ExportToExcel(gvDetail, "Report");
}
}
public override void VerifyRenderingInServerForm(Control control)
{
/* Confirms that an HtmlForm control is rendered for the specified ASP.NET
server control at run time. */
}
Tim Schmelter's answer helped me a lot, but I had to do one more thing to get it to work on my aspx page. I am using this code to email an embedded GridView control (as HTML), for report automation.
In addition to adding the override sub, I had to do the render() in Me.Handles.onunload, or else I got an error on the RenderControl line.
Protected Sub Page_After_load(sender As Object, e As EventArgs) Handles Me.Unload
If runningScheduledReport Then
Dim stringBuilder As StringBuilder = New StringBuilder()
Dim stringWriter As System.IO.StringWriter = New System.IO.StringWriter(stringBuilder)
Dim htmlWriter As HtmlTextWriter = New HtmlTextWriter(stringWriter)
GridView1.RenderControl(htmlWriter)
Dim htmlcode As String = stringBuilder.ToString()
Func.SendEmail(Context.Request.QueryString("email").ToString, htmlcode, "Auto Report - Agent Efficiency", Nothing)
End If
End Sub

I can't get the custom control to change rendering of a master page control

I have a master page with a placeholder control.
I have a page which inherits from master page.
I then have a custom control which is displayed on the page, this custom control has a cast to the masterpage so I can access the placeholder control to turn visibility on and off. Everything works as expected when I watch it in the debugger, but the placeholder control fails to turn it's visibility off.
I feel this has something to do in the order in which the events are firing. It appears any code in the custom control on the page is firing after the masterpage has already rendered.
Does anybody have any idea how I can affect the way this page is rendered so the custom control can turn the placeholder and on and off?
the code in the control looks like this;
protected override void Render(HtmlTextWriter writer)
{
var master = this.Page.Master as Site;
if (master != null) // cast failed, your master is a different type
{
master.NavBar.Visible = false;
}
// other stuff
}
Include the MasterType tag in your page, so that you dont need to typecase the page.Master, directly you can get the Master instance.
The solution to this problem was the order in which the control, masterpage and page were being fired, it was ignoring the setting on the custom control. The solution is to add this functionality to the custom control on the OnPreRender(EventArgs e) method.
protected override void OnPreRender(EventArgs e)
{
var master = this.Page.Master as Site;
if (master != null) // cast failed, your master is a different type
{
var progressShown = master.FindControl("ProgressShown");
if (progressShown != null)
{
master.NavBar.Attributes.Add("class", "test");
}
}
base.OnPreRender(e);
}

Override SharePoint:SaveButton in custom form template

First let me clear the air and post articles which already explain how to override the SaveButton:
How to override or customize the Sharepoint SaveButton?
How to override functionality of the Ribbon Save button
Override SharePoint Save Button to Provide Custom Functionality
I have read those and understood them, I just don't know how to fully implement it in my particular case:
I have a custom rendering template "CustomRender" which includes the "real form". The code for the real form looks something around these lines:
<%# Register TagPrefix="wssuc" TagName="ToolBar"
src="~/_controltemplates/ToolBar.ascx" %>
<%# Control Language="C#" AutoEventWireup="true"
CodeBehind="RealForm.ascx.cs" Inherits="CustomNameSpace.CustomForm" %>
<p>Test</p>
<wssuc:ToolBar runat="server" id="toolbar">
<TemplateButtons>
<SharePoint:SaveButton runat="server" />
</TemplateButtons>
</wssuc:ToolBar>
Now I want to override this save button. The sites above state that I just have to write another control which overrides the button. E.g.:
public class NewSaveButton: SaveButton
{
protected override bool SaveItem()
{
bool success = base.SaveItem();
RedirectUrl = String.Concat(List.ParentWeb.ServerRelativeUrl, "/",
List.Forms[PAGETYPE.PAGE_DISPLAYFORM].Url, #"?ID=",
ListItem.ID, #"&Source=", ListItem.ParentList.DefaultViewUrl);
return success;
}
}
Now I just don't know how to register this template inside my other template. Could I not just override the SaveButton in the Code behind of my template - how would I do that and reference it later on?
Option one: Code-Behind of the form (RealForm.ascx.cs) - can I just put the override method in there? How can I reference the button then in the form (how do I get <NewSaveButton>)?
Option two: Another template just for the button, e.g. SaveButton.ascx" - how do I reference that via <%# Register... %>, i.e. how do I know PublicKeyToken etc. when deployed via a Feature. And same thing here: My goal is to get some kind of "<NewSaveButton>" control for the form.
You're creating a new server control when you do this, so you'll need to register the new control on the page (or in this case, in the template .ascx file).
<%# Register TagPrefix="MyPrefix" Namespace="ControlNamespace" Assembly="MyFullyQualifiedAssembly" %>
In your code file you can to add the ToolboxDataAttribute to the class (this is only necessary if you are dragging&dropping the control from the toolbox in visual studio)
[ToolboxData("<{0}:NewSaveButton runat=\"server\"></{0}:NewSaveButton>")]
public class NewSaveButton : SaveButton {}
Now, you should be able to replace the save button on the form with the following:
<MyPrefix:NewSaveButton runat="server"></MyPrefix:NewSaveButton>
You're basically creating a new server control following the rules of asp.net (no sharepoint specific stuff is happening here).
For more information, take a look at this page: http://msdn.microsoft.com/en-us/library/yhzc935f(v=VS.85).aspx
On your page with SaveButton you could do the following trick (in my case save button is added in DataFormWebPart's XSL markup):
// On your page with SaveButton you could do the following trick
// (in my case save button is added in DataFormWebPart's XSL markup):
SPContext itemContext;
DataFormWebPart dataForm; // from designer's code behind
void Page_Init(object sender, EventArgs e)
{
// NOTE: by some reason ItemContexts of controls in DFWP are differ,
// so only SaveButton's OnSaveHandler is invoked
itemContext = dataForm.Controls.FindControlRecursive<SaveButton>().ItemContext;
}
void Page_Load(object sender, EventArgs e)
{
if (itemContext.FormContext.FormMode == SPControlMode.New ||
itemContext.FormContext.FormMode == SPControlMode.Edit)
{
itemContext.FormContext.OnSaveHandler += OnSaveHandler;
}
}
void OnSaveHandler(object sender, EventArgs eventArgs)
{
// TODO: Add your code before saving the item
SaveButton.SaveItem(saveButton.ItemContext, false, string.Empty);
// TODO: Add your code after saving the item
}
The FindControlRecursive() extension implementation is
public static class ControlExtensions
{
public static TControl FindControlRecursive<TControl>
(
this ControlCollection controls
) where TControl : Control
{
if (controls != null)
{
foreach (Control control in controls)
{
var foundControl = control as TControl
?? control.Controls.FindControlRecursive();
if (foundControl != null)
{
return foundControl;
}
}
}
return null;
}
}

Add ScriptManager to Page Programmatically?

I am developing a WebPart (it will be used in a SharePoint environment, although it does not use the Object Model) that I want to expose AJAX functionality in. Because of the nature of the environment, Adding the Script Manager directly to the page is not an option, and so must be added programmatically. I have attempted to add the ScriptManager control to the page in my webpart code.
protected override void CreateChildControls()
{
if (ScriptManager.GetCurrent(Page) == null)
{
ScriptManager sMgr = new ScriptManager();
// Ensure the ScriptManager is the first control.
Page.Form.Controls.AddAt(0, sMgr);
}
}
However, when this code is executed, I get the following error message:
"The control collection cannot be modified during DataBind, Init, Load, PreRender or Unload phases."
Is there another way to add the ScriptManager to the page from a WebPart, or am I going to have to just add the ScriptManager to each page (or master page) that will use the WebPart?
I was able to get this to work by using the Page's Init event:
protected override void OnInit(EventArgs e)
{
Page.Init += delegate(object sender, EventArgs e_Init)
{
if (ScriptManager.GetCurrent(Page) == null)
{
ScriptManager sMgr = new ScriptManager();
Page.Form.Controls.AddAt(0, sMgr);
}
};
base.OnInit(e);
}
I had the same basic issue the rest of you had. I was creating a custom ascx control and wanted to be able to not worry about whether or not the calling page had the scriptmanager declared. I got around the issues by adding the following to the ascx contorl itself.
to the ascx page -
<asp:PlaceHolder runat="server" ID="phScriptManager"></asp:PlaceHolder>
in the update panel itself - oninit="updatePanel1_Init"
to the ascx.cs file -
protected void updatePanel1_Init(object sender, EventArgs e)
{
if (ScriptManager.GetCurrent(this.Page) == null)
{
ScriptManager sManager = new ScriptManager();
sManager.ID = "sManager_" + DateTime.Now.Ticks;
phScriptManager.Controls.AddAt(0, sManager);
}
}
Thank you to everyone else in this thread who got me started.
I've done this and it works. Create a placeholder for the controls:
<asp:PlaceHolder ID="WebGridPlaceholder" runat="server" >
</asp:PlaceHolder>
Then you can do this in CreateChildControls:
ScriptManager aSM = new ScriptManager();
aSM.ID = "GridScriptManager";
WebGridPlaceholder.Controls.Add(aSM);
I ran into this problem with a custom ascx server control. I tried many solutions involving adding script to the OnInit events of the control (which doesn't get executed until after it checks for the ScriptManager control), adding logic inside of server tags on the control, and adding things to about every other event. No good. I finally built a control that inherits from ScriptManagerProxy and then uses ktrauberman's piece of code, slightly modified, to add a ScriptManager if needed:
public class ProxiedScriptManager : ScriptManagerProxy
{
protected override void OnInit(EventArgs e)
{
//double check for script-manager, if one doesn't exist,
//then create one and add it to the page
if (ScriptManager.GetCurrent(this.Page) == null)
{
ScriptManager sManager = new ScriptManager();
sManager.ID = "sManager_" + DateTime.Now.Ticks;
Controls.AddAt(0, sManager);
}
base.OnInit(e);
}
}
That did it for me.
This is the only way I could get my update panel to work in a sharepoint 2007 / 2010 compatible webpart. We use a 2010 master page with an scriptmanager but a 2007 master page without one.
.ascx
<asp:PlaceHolder ID="sMgr_place" runat="server" />
<asp:UpdatePanel runat="server" OnInit="updatePanel_Init"><ContentTemplate>
...
</ContentTemplate></asp:UpdatePanel>
.ascx.cs
public void updatePanel_Init(object sender, EventArgs e)
{
if (ScriptManager.GetCurrent(Page) == null)
{
ScriptManager sMgr = new ScriptManager();
sMgr.EnablePartialRendering = true;
sMgr_place.Controls.Add(sMgr);
}
}
I used this code in custom web controls (.cs) that contain update panels.
protected override void OnInit(EventArgs e)
{
//...
if (ScriptManager.GetCurrent(this.Page) == null)
{
ScriptManager scriptManager = new ScriptManager();
scriptManager.ID = "scriptManager_" + DateTime.Now.Ticks;
Controls.AddAt(0, scriptManager);
}
//...
}
I had this similar problem and found the best way was to add a global ScriptManager to the masterpage then in the code behind you can add to it by:
ScriptManager.GetCurrent(Page).Services.Add(new ServiceReference(virtualPath));

Categories