GridView muss in einem Formular-Tag mit runat = "server" platziert werden, auch wenn sich GridView in einem Formular-Tag befindet

85
<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 dahinter:

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

Sogar die GridView befindet sich in einem from-Tag mit runat = "server", dennoch wird dieser Fehler angezeigt.

Irgendwelche Hinweise bitte?

Teenup
quelle
2
Ich habe dies schon einmal gesehen, wenn jemand eine Masterseite verwendet, die bereits ein Formular-Tag hat (das möglicherweise bereits runat="server"in seinem <form>Tag deklariert ist oder nicht ). Nur ein Gedanke ...
lhan
@Lloyd: Aber ich habe keine Masterseite, ich habe diese Seite nur zum Testen dieses Fehlers erstellt.
Teenup
Hallo, ich habe Ihren Code kopiert, kann das Problem jedoch nicht replizieren. Können Sie bitte den gesamten Dateiinhalt (jede Zeile) in Ihre Frage einfügen oder einfügen? Danke
christofr

Antworten:

172

Sie rufen an GridView.RenderControl(htmlTextWriter), daher löst die Seite eine Ausnahme aus, dass ein Server-Control außerhalb eines Formulars gerendert wurde.

Sie könnten diese execption vermeiden durch zwingende VerifyRenderingInServerForm

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

Sehen Sie hier und hier .

Tim Schmelter
quelle
Ich habe eine GridView, deren Inhalt ich in eine E-Mail-Nachricht rendern möchte. Deshalb muss ich sie aus der Form rendern. Ich kann diese Methode nicht überschreiben, da die Hostseite von Sharepoint ist. Mein Raster ist eine Benutzersteuerung in einem Webpart auf einer Sharepoint-Seite.
Teenup
Wenn ich diese GridView direkt dynamisch zu einer HTML-Form hinzufüge und sie dann rendere, wird sie perfekt gerendert. Dies bedeutet, dass nur ein Formular außerhalb des Rasters vorhanden sein muss. Wenn ich diesen DIV jedoch dynamisch zur HtmlForm hinzufüge, tritt dieser Fehler erneut auf, obwohl das Grid ein untergeordnetes Element von DIV ist und zusammen mit dieser auch zu HtmlForm hinzugefügt wird.
Teenup
Dies funktioniert nicht, wenn sich Ihr Raster in einem .ascx-Benutzersteuerelement befindet. In diesem Fall siehe Chris Mullins Antwort unten. Ich habe sowohl Tims als auch Chris 'Techniken verwendet und sie funktionieren großartig.
Taylor Brown
Ich liebe eine elegante Lösung! Macht mich aufgeregt: D
Nikolay
3
Hat super funktioniert. Nur ein Kopf hoch wird möglicherweise die Fehlermeldung "RegisterForEventValidation kann nur während Render () aufgerufen werden;" angezeigt. Wenn dies der Fall ist, stellen Sie sicher, dass die EventValidation im Markup für die Seite auf false gesetzt ist.
Al Belmondo
29

Eine Alternative zum Überschreiben von VerifyRenderingInServerForm besteht darin, das Raster während des Renderns aus der Steuerelementauflistung zu entfernen und es dann wieder hinzuzufügen, wenn Sie fertig sind, bevor die Seite geladen wird. Dies ist hilfreich, wenn Sie eine generische Hilfsmethode zum Abrufen von Grid-HTML benötigen, da Sie nicht daran denken müssen, die Überschreibung hinzuzufügen.

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

Eine andere Alternative, um das Überschreiben zu vermeiden, besteht darin, Folgendes zu tun:

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
quelle
Geschickt!! Ich werde es morgen versuchen.
Teenup
Beim Versuch, das Raster in einem asp-Benutzersteuerelement (.ascx) zu rendern, hat die Verwendung der ersten Methode für mich hervorragend funktioniert.
Taylor Brown
3
1. Es funktioniert nicht, wenn die Rasteransicht Steuerelemente wie LinkButton enthält. Es gibt "Steuerelement vom Typ" LinkButton "muss in einem Formular-Tag mit dem Fehler" runat = server "platziert werden. 2. Könnten Sie bitte erklären, warum diese Technik funktioniert?
BornToCode
@BornToCode Deaktivieren Sie die Sortierung für Ihre Rasteransicht im Code.
Adi Solar
14

Fügen Sie direkt nach Ihrem Page Load Folgendes hinzu:

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

Beachten Sie, dass ich in der Funktion nichts mache.

EDIT: Tim antwortete das gleiche. :) Sie können auch die Antwort finden hier

Ivan Nikolov
quelle
2

Ich möchte nur eine andere Möglichkeit hinzufügen, dies zu tun. Ich habe mehrere Personen in verschiedenen verwandten Threads gesehen, die gefragt haben, ob Sie VerifyRenderingInServerForm verwenden können, ohne es der übergeordneten Seite hinzuzufügen.

Sie können dies tatsächlich tun, aber es ist ein bisschen bodge.

Erstellen Sie zunächst eine neue Seitenklasse, die ungefähr so ​​aussieht:

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

Es muss keine .ASPX zugeordnet sein.

Dann können Sie in dem Steuerelement, das Sie rendern möchten, Folgendes tun.

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

Jetzt haben Sie Ihr ursprüngliches Steuerelement als HTML gerendert. Wenn nötig, fügen Sie das Steuerelement wieder in seine ursprüngliche Position ein. Sie haben jetzt den HTML-Code gerendert, die Seite wie gewohnt und keine Änderungen an der Seite selbst vorgenommen.

Daniel Edwards
quelle
@DanielEdwards Was macht DesignerInitialize () für Sie?
JJS
Dies funktioniert, aber ich musste es verwenden HttpContext.Current.Server.Execute(page, writer, false);, um den HTML-Code zu schreiben. Der Aufruf controlToRender.RenderControl(hw);hat keines der Steuerelementereignisse ausgelöst, z. B. Page_Loadwährend das Steuerelement gerendert wurde, war es leer.
DGibbs
0

Hier ist mein 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
quelle
Warum haben Sie diese Antwort 5 Jahre nach ihrer Beantwortung hinzugefügt? Und es ist die gleiche Antwort.
Mukus