Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UserControl's RenderControl is asking for a form tag in (C# .NET)

I asked how to render a UserControl's HTML and got the code working for a dynamically generated UserControl.

Now I'm trying to use LoadControl to load a previously generated Control and spit out its HTML, but it's giving me this:

Control of type 'TextBox' must be placed inside a form tag with runat=server.

I'm not actually adding the control to the page, I'm simply trying to grab its HTML. Any ideas?

Here's some code I'm playing with:

TextWriter myTextWriter = new StringWriter();
HtmlTextWriter myWriter = new HtmlTextWriter(myTextWriter);

UserControl myControl = (UserControl)LoadControl("newUserControl.ascx");
myControl.RenderControl(myWriter);

return myTextWriter.ToString();
like image 496
Jon Smock Avatar asked Dec 02 '08 15:12

Jon Smock


Video Answer


2 Answers

Alternatively you could disable the ServerForm/Event-validation on the page that is rendering the control to a string.

The following example illustrates how to do this.

public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        string rawHtml = RenderUserControlToString();
    }

    private string RenderUserControlToString()
    {
        UserControl myControl = (UserControl)LoadControl("WebUserControl1.ascx");

        using (TextWriter myTextWriter = new StringWriter())
        using (HtmlTextWriter myWriter = new HtmlTextWriter(myTextWriter))
        {
            myControl.RenderControl(myWriter);

            return myTextWriter.ToString();
        }
    }

    public override void VerifyRenderingInServerForm(Control control)
    { /* Do nothing */ }

    public override bool EnableEventValidation
    {
        get { return false; }
        set { /* Do nothing */}
    }
}
like image 91
Tom Jelen Avatar answered Oct 21 '22 23:10

Tom Jelen


This is a dirty solution I used for the moment (get it working then get it right, right?).

I had already created a new class that inherits the UserControl class and from which all other "UserControls" I created were derived. I called it formPartial (nod to Rails), and this is going inside the public string renderMyHTML() method:

TextWriter myTextWriter = new StringWriter();
HtmlTextWriter myWriter = new HtmlTextWriter(myTextWriter);

UserControl myDuplicate = new UserControl();
TextBox blankTextBox;

foreach (Control tmpControl in this.Controls)
{
    switch (tmpControl.GetType().ToString())
    {
        case "System.Web.UI.LiteralControl":
            blankLiteral = new LiteralControl();
            blankLiteral.Text = ((LiteralControl)tmpControl).Text;
            myDuplicate.Controls.Add(blankLiteral);
            break;
        case "System.Web.UI.WebControls.TextBox":
            blankTextBox = new TextBox();
            blankTextBox.ID = ((TextBox)tmpControl).ID;
            blankTextBox.Text = ((TextBox)tmpControl).Text;
            myDuplicate.Controls.Add(blankTextBox);
            break;

            // ...other types of controls (ddls, checkboxes, etc.)

    }
}

myDuplicate.RenderControl(myWriter);
return myTextWriter.ToString();

Drawbacks off the top of my head:

  1. You need a case statement with every possible control (or controls you expect).
  2. You need to transfer all the important attributes from the existing control (textbox, etc) to the new blank control.
  3. Doesn't take full advantage of Controls' RenderControl method.

It'd be easy to mess up 1 or 2. Hopefully, though, this helps someone else come up with a more elegant solution.

like image 36
Jon Smock Avatar answered Oct 21 '22 22:10

Jon Smock