Artificially firing Page Events in ASP.NET? - c#

I'm working with a static class in C#, and am trying to use Control.RenderControl() to get a string / mark-up representation of a Control.
Unfortunately the control (and all child controls) use event bubbling to populate certain values, for example, when instantiating, then calling RenderControl() on the following:
public class MyTest : Control
{
protected override void OnLoad(EventArgs e)
{
this.Controls.Add(new LiteralControl("TEST"));
base.OnLoad(e);
}
}
I am returned an empty string, because OnLoad() is never fired.
Is there a way I can invoke a 'fake' page lifecycle? Perhaps use some dummy Page control?

I was able to accomplish this by using a local instance of Page and HttpServerUtility.Execute:
// Declare a local instance of a Page and add your control to it
var page = new Page();
var control = new MyTest();
page.Controls.Add(control);
var sw = new StringWriter();
// Execute the page, which will run the lifecycle
HttpContext.Current.Server.Execute(page, sw, false);
// Get the output of your control
var output = sw.ToString();
EDIT
If you need the control to exist inside a <form /> tag, then simply add an HtmlForm to the page, and add your control to that form like so:
// Declare a local instance of a Page and add your control to it
var page = new Page();
var control = new MyTest();
// Add your control to an HTML form
var form = new HtmlForm();
form.Controls.Add(control);
// Add the form to the page
page.Controls.Add(form);
var sw = new StringWriter();
// Execute the page, which will in turn run the lifecycle
HttpContext.Current.Server.Execute(page, sw, false);
// Get the output of the control and the form that wraps it
var output = sw.ToString();

Related

How can I force Master Render event to fire with partial rendering enabled?

I have some code in the Render event of my Master page that needs to be run on every postback, as it's used to translate some of the HTML content. However, the event does not seem to trigger on postback when I'm using an UpdatePanel and a ScriptManager with partial rendering set to true. Can I force the event to fire, or can I run my code elsewhere to produce the same result?
protected override void Render(HtmlTextWriter writer)
{
string originalContent = String.Empty;
string translatedContent = String.Empty;
using (StringWriter sw = new StringWriter())
{
using (HtmlTextWriter htw = new HtmlTextWriter(sw))
{
base.Render(htw);
htw.Close();
originalContent = sw.ToString();
}
}
// Translate content:
translatedContent = ApplyGlobalization(Page, originalContent);
// Write updated HTML:
writer.Write(translatedContent);
}
Solved the problem by creating my own UpdatePanel with Render overridden. I put the same code into that method, but had to make some changes to adjust to the translation method to accustom to the special output that the UpdatePanel creates on partial postback.

Overriding VerifyRenderingInServerForm on dynamically created Pages()

I was having some problems regarding the creation of a Page dynamically I do :
p = New Page();
Page myPage = new Page();
FormAtt ctrl = (FormAtt)myPage.LoadControl("path/to/my/file.ascx"); // here lies the gridview of evil
myPage.Controls.Add(ctrl);
Problem is i receive
Control ... must be placed inside a form tag with runat=server
Ok, so I've found out that I Need to override the VerifyRenderingInServerForm method to be able to call a formless page, But how can i override VerifyRenderingInServerForm since i don't have a ASPX file.
ps: I have a related question and I don't know what to do, since they are different questions but the solution goes to the same problema , and I gave up on the last solution - see : Form is Null in Dynamically created Pages
You can try to use a custom class which already overrides VerifyRenderingInServerForm:
public partial class MyCustomPage : System.Web.UI.Page
{
public override void VerifyRenderingInServerForm(Control control)
{
}
protected void Page_Load(object sender, EventArgs e)
{
var p = new MyCustomPage();
FormAtt uc = (FormAtt)p.LoadControl("path/to/my/file.ascx");
p.Controls.Add(uc);
}
}
Similar to your previous question. You need to add HtmlForm first. ASP.Net need a form tag in order to add controls to a page.
Page myPage = new Page();
HtmlForm form = new HtmlForm();
FormAtt ctrl = (FormAtt)myPage.LoadControl("path/to/my/file.ascx");
form.Controls.Add(ctrl);
myPage.Controls.Add(form);
i do it to render a component
System.IO.StringWriter stringWrite = new System.IO.StringWriter();
System.Web.UI.HtmlTextWriter htmlWrite = new HtmlTextWriter(stringWrite);
Page p = new Page();
System.Web.UI.HtmlControls.HtmlForm form = new System.Web.UI.HtmlControls.HtmlForm();
p.Controls.Add(form);
form.Controls.Add(gv);
form.RenderControl(htmlWrite);
string j = stringWrite.ToString();

Loading a user control dynamically

I'm trying to load a user control in a web service, but it doesn't execute the Load_Page().
I tried to use:
HttpContext.Current.Server.Execute(page, text, false);
But it returns a NullException. It is my code:
public string Controle(string url)
{
Page page = new Page();
UserControl userControl = (UserControl)page.LoadControl(url);
//userControl.EnableViewState = false;
HtmlForm form = new HtmlForm();
form.Controls.Add(userControl);
page.Controls.Add(form);
StringWriter text = new StringWriter();
HtmlTextWriter htmltext = new HtmlTextWriter(text);
userControl.RenderControl(htmltext);
return text.ToString();
}
Hope it is clear.
You need to initialize the control using a method that does something like
this.Load += Page_Load;
Please refer to this post which explains exactly what needs to be done to achieve this. Be sure to read the section stating; "One word of caution:"
http://weblogs.asp.net/srkirkland/archive/2007/11/05/dynamically-render-a-web-user-control.aspx
This related post will also be able to assist:
Page_Load not firing in UserControl

How call GetWebResourceUrl() when Page is null ?

I built custom ASP.NET control and it's working fine when I add it manually (drag and drop) or by code to controls in markup.
The custom control, MsgBox, had resources like JavaScript, CSS and images embedded in and the problem appeared when I tried to Render the control in class to return its HTML code, the Page instance is null and the "GetWebResourceUrl" needs it:
Page.ClientScript.GetWebResourceUrl(.....)
is there any way to get the resourceurl ? Here is my render code:
protected override void RenderContents(HtmlTextWriter writer)
{
using (PlaceHolder plh = new PlaceHolder())
{
if (Page != null)
{
if (DesignMode || Page.Header == null)
RegisterCSSInclude(plh);
}
HtmlGenericControl container = new HtmlGenericControl("div");
container.EnableViewState = false;
container.InnerHtml = "Control html code";
plh.Controls.Add(container);
plh.RenderControl(writer);
}
}
RegisterCSSInclude is method to register my css files:
private void RegisterCSSInclude(Control target)
{
// CSS
bool linkIncluded = false;
foreach (Control c in target.Controls)
{
if (c.ID == "MsgBxStyle")
{
linkIncluded = true;
}
}
if (!linkIncluded)
{
HtmlGenericControl globalCsslink = new HtmlGenericControl("link");
globalCsslink.ID = "MsgBxGStyle";
globalCsslink.Attributes.Add("href", Page.ClientScript.GetWebResourceUrl(typeof(MessageBoxCtrl), "MessageBox.MsgBxStyles.WeDevMsgBox.css"));
globalCsslink.Attributes.Add("type", "text/css");
globalCsslink.Attributes.Add("rel", "stylesheet");
globalCsslink.EnableViewState = false;
target.Controls.Add(globalCsslink);
HtmlGenericControl csslink = new HtmlGenericControl("link");
csslink.ID = "MsgBxStyle";
csslink.Attributes.Add("href", Page.ClientScript.GetWebResourceUrl(typeof(MessageBoxCtrl), "MessageBox.MsgBxStyles." + Style.ToString().ToLower() + ".css"));
csslink.Attributes.Add("type", "text/css");
csslink.Attributes.Add("rel", "stylesheet");
csslink.EnableViewState = false;
target.Controls.Add(csslink);
}
}
Update:
PS: I'm tring to use control in generic handler (ashx) where I call ShowMsgBox method which is a method in a class and not in a page or user control.
ShowMsgBox method should create an instance of MsgBox control and render it then return the html code to ashx class :
var htmlCode = MyClass.ShowMsgBox("myMsg");
context.Response.write(htmlCode);
I built a custom ASP.NET control ...
I'm tring to use control in generic handler (ashx) ... not in a page or user control.
A Page is a handler. You want to use a convenience provided by the Page class, but you don't want to inherit from Page. The niceties of Page, such as ClientScript, expect a Page from which to get various information.
You can provide a dummy Page object to your control by setting the Page property of your custom Control:
this.Page = new Page();
...then you will need to set various properties (assuming they are public) which are expected by ClientScriptManager.GetWebResourceUrl():
this.Page.Foo = "bar";
then you can call:
this.Page.ClientScript.GetWebResourceUrl(...);
If this is the specific class that inherits from WebControl page shouldn't be null. If its another class that you are rendering as part of a hierarchy you can add a parameter of type Page and pass the reference of the current page to it.

GridView must be placed inside a form tag with runat="server" even after the GridView is within a form tag

<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

Categories

Resources