GridView doit être placé dans une balise de formulaire avec runat = "server" même après que GridView se trouve dans une balise de formulaire

86
<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 derrière:

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();
    }
}

Même le GridView est dans une balise from avec runat = "server", j'obtiens toujours cette erreur.

Des indices s'il vous plait?

adolescent
la source
2
J'ai déjà vu cela si quelqu'un utilise une page maître qui a déjà une balise de formulaire (qui peut ou non être déjà déclarée runat="server"dans sa <form>balise). Juste une pensée ...
lhan
@Lloyd: Mais je n'ai pas de page maître, j'ai créé cette page uniquement pour tester cette erreur.
teenup le
Bonjour, j'ai copié votre code mais je ne parviens pas à reproduire le problème. Pouvez-vous s'il vous plaît mettre tout le contenu du fichier (chaque ligne) dans votre question, ou le coller? Merci
christofr

Réponses:

174

Vous appelez GridView.RenderControl(htmlTextWriter), donc la page lève une exception selon laquelle un contrôle serveur a été rendu en dehors d'un formulaire.

Vous pouvez éviter cette exécution en remplaçant VerifyRenderingInServerForm

public override void VerifyRenderingInServerForm(Control control)
{
  /* Confirms that an HtmlForm control is rendered for the specified ASP.NET
     server control at run time. */
}

Voir ici et ici .

Tim Schmelter
la source
J'ai un GridView dont je veux rendre le contenu dans un message électronique, c'est pourquoi je dois le rendre hors forme. Je ne peux pas remplacer cette méthode car la page hôte est de Sharepoint. My Grid est un Usercontrol dans un composant WebPart dans une page sharepoint.
teenup le
De plus, lorsque j'ajoute ce GridView directement à un HtmlForm dynamiquement, puis que je le rende, il rend parfaitement. Cela signifie qu'il ne nécessite que la présence d'un formulaire hors grille. Mais, lorsque j'ajoute dynamiquement ce DIV au HtmlForm, cette erreur survient à nouveau, bien que le Grid soit un enfant de DIV et également ajouté à HtmlForm avec lui.
teenup le
cela ne fonctionnera pas si votre grille se trouve dans un contrôle utilisateur .ascx. dans ce cas, voir la réponse de Chris Mullins ci-dessous. J'ai utilisé les techniques de Tim et Chris et elles fonctionnent très bien.
Taylor Brown
J'adore une solution élégante! M'excite: D
Nikolay
3
A très bien fonctionné. Juste un avertissement, vous pouvez obtenir une erreur disant "RegisterForEventValidation ne peut être appelé que pendant Render ();" Si tel est le cas, assurez-vous de définir EventValidation sur false dans le balisage de la page.
Al Belmondo
29

Une alternative à la substitution de VerifyRenderingInServerForm consiste à supprimer la grille de la collection de contrôles pendant que vous effectuez le rendu, puis à la rajouter lorsque vous avez terminé avant le chargement de la page. Ceci est utile si vous souhaitez avoir une méthode d'assistance générique pour obtenir le code HTML de la grille, car vous n'avez pas à vous rappeler d'ajouter le remplacement.

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);
}

Une autre alternative pour éviter le remplacement est de faire ceci:

grid.RenderBeginTag(hw);
grid.HeaderRow.RenderControl(hw);
foreach (GridViewRow row in grid.Rows)
{
    row.RenderControl(hw);
}
grid.FooterRow.RenderControl(hw);
grid.RenderEndTag(hw);
Chris Mullins
la source
Adroit!! Je vais l'essayer demain.
teenup le
en essayant de rendre la grille dans un contrôle utilisateur asp (.ascx), l'utilisation de la 1ère méthode a très bien fonctionné pour moi.
Taylor Brown
3
1. Cela ne fonctionne pas si gridview contient des contrôles comme LinkButton - il donne 'Le contrôle de type' LinkButton 'doit être placé dans une balise de formulaire avec l'erreur runat = server'. 2.Pouvez-vous expliquer pourquoi cette technique fonctionne-t-elle?
BornToCode
@BornToCode Désactivez le tri pour votre grille dans le code.
Adi Solar
14

Juste après votre Page Load, ajoutez ceci:

public override void VerifyRenderingInServerForm(Control control)
{
    //base.VerifyRenderingInServerForm(control);
}

Notez que je ne fais rien dans la fonction.

EDIT: Tim a répondu à la même chose. :) Vous pouvez également trouver la réponse ici

Ivan Nikolov
la source
2

Je veux juste ajouter une autre façon de faire cela. J'ai vu plusieurs personnes sur divers threads connexes vous demander si vous pouvez utiliser VerifyRenderingInServerForm sans l'ajouter à la page parent.

En fait, vous pouvez le faire, mais c'est un peu bizarre.

Commencez par créer une nouvelle classe Page qui ressemble à ceci:

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*/ }
    }
}

N'a pas besoin d'avoir un .ASPX associé.

Ensuite, dans le contrôle que vous souhaitez rendre, vous pouvez faire quelque chose comme ce qui suit.

    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);

Votre contrôle d'origine est maintenant rendu au format HTML. Si vous en avez besoin, remettez le contrôle dans sa position d'origine. Vous avez maintenant le HTML rendu, la page comme d'habitude et aucune modification de la page elle-même.

Daniel Edwards
la source
@DanielEdwards que fait DesignerInitialize () pour vous?
JJS
Cela fonctionne mais j'avais besoin d'utiliser HttpContext.Current.Server.Execute(page, writer, false);pour écrire le HTML - l'appel controlToRender.RenderControl(hw);n'a déclenché aucun des événements de contrôle, par exemple Page_Load, pendant le rendu du contrôle, il était vide.
DGibbs
0

Voici mon 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. */
    }
vipin
la source
Pourquoi avez-vous ajouté cette réponse 5 ans après sa réponse? Et c'est la même réponse.
Mukus