摘要

GridView 控制項常有需要匯出 Excel 的需求,一般都是將 GridView 使用 RenderControl 來輸出其 HTML 程式碼。本文即在討論 RenderControl 所產生的問題及解決方式,不過本文是透過 BasePage 的方式,讓 RenderControl 的相關處理動作更簡化。

手動解決 RenderControl 所產生的問題

下面的 ControlToHTML 函式,主要是將控制項轉換為對應的 HTML 程式碼。

    ''' <summary>
    ''' 將控制項轉換為對應的 HTML 程式碼。
    ''' </summary>
    ''' <param name="Control">控制項。</param>
    Public Shared Function ControlToHTML(ByVal Control As System.Web.UI.Control) As String
        Dim sHTML As String = String.Empty
        Dim oTextWriter As New System.IO.StringWriter()
        Dim oHTMLWriter As New System.Web.UI.HtmlTextWriter(oTextWriter)

        Control.RenderControl(oHTMLWriter)
        sHTML = oTextWriter.ToString()
        Return sHTML
    End Function

你可以整個 GridView 控制項傳入 ControlToHTML 來取得它的 HTML 程式碼,不過當執行此方法時,會遇到由 Page.VerifyRenderingInServerForm 方法釋出的錯誤訊息。

當執行下面的程式碼時

Dim sHTML As String = ControlToHTML(GridView1)

會產生錯誤訊息

型別 'GridView' 的控制項 'GridView1' 必須置於有 runat=server 的表單標記之中。

要解決這個問題就是讓 Page 不要執行 VerifyRenderingInServerForm 方法,所以 Page 要覆寫 VerifyRenderingInServerForm 方法,而不做任何事。

Public Overrides Sub VerifyRenderingInServerForm(ByVal Control As System.Web.UI.Control)
     '覆寫,不執行 MyBase.VerifyRenderingInServerForm 方法,解決執行 RenderControl 產生的錯誤
End Sub

接下來繼續執行程式,若 GridView 有 CommandFIeld 或分頁時,它會去做事件驗證的動作,而會引發另一個錯誤訊息

RegisterForEventValidation 只能在 Render(); 期間呼叫

要解決這個問題,可以切換到 aspx 程式碼中,在 <%@ Page %> 中加入 EnableEventValidation="false" 即可。

<%@ Page Language="VB" AutoEventWireup="false" EnableEventValidation="false" CodeFile="Default.aspx.vb" Inherits="_Default" %>

 

 

使用 BasePage 解決 RenderControl 所產生的問題

雖然上述的方式可以解決 RenderControl 產生的問題,可是似乎有點太麻煩,有沒有更簡單的方式呢?我們用 BasePage 來處理這個問題,不用當有這類需求時還要去手動故這些設定。

TBBasePage 繼承 Page,新增一個 IsVerifyRender 屬性(預設為 True),來決定是否執行 MyBase.VerifyRenderingInServerForm 方法。首先覆寫 VerifyRenderingInServerForm 方法,當 IsVerifyRender="False" 時,不會去執行 MyBase.VerifyRenderingInServerForm 方法;另外覆寫 EnableEventValidation 方法,當 IsVerifyRender="False" 則傳回 False。當我們要用 RenderControl 來輸出控制項的 HTML 碼時,只需先設定 IsVerifyRender = "False" 即可。

''' <summary>
''' 頁面基礎類別。
''' </summary>
Public Class TBBasePage
    Inherits System.Web.UI.Page

    Private FIsVerifyRender As Boolean = True

    ''' <summary>
    ''' 是否執行 VerifyRenderingInServerForm 方法。
    ''' </summary>
    Public Property IsVerifyRender() As Boolean
        Get
            Return FIsVerifyRender
        End Get
        Set(ByVal value As Boolean)
            FIsVerifyRender = value
        End Set
    End Property

    ''' <summary>
    ''' 覆寫。
    ''' </summary>
    ''' <param name="Control"></param>
    ''' <remarks></remarks>
    Public Overrides Sub VerifyRenderingInServerForm(ByVal Control As System.Web.UI.Control)
        If Me.IsVerifyRender Then
            MyBase.VerifyRenderingInServerForm(Control)
        End If
    End Sub

    ''' <summary>
    ''' 覆寫。啟用事件驗證動作。
    ''' </summary>
    Public Overrides Property EnableEventValidation() As Boolean
        Get
            If Me.IsVerifyRender Then
                Return MyBase.EnableEventValidation
            Else
                Return False
            End If
        End Get
        Set(ByVal value As Boolean)
            MyBase.EnableEventValidation = value
        End Set
    End Property

End Class

有了 TBBasePage 的 IsVerifyRender 屬性後,我們就可以將上述的 ControlToHTML 函式,改寫如下。當 GridView 控制項置放在 TBBasePage 時,執行 ControlToHTML 函式時,不需另行設定即能正常執行。

    ''' <summary>
    ''' 將控制項轉換為對應的 HTML 程式碼。
    ''' </summary>
    ''' <param name="Control">控制項。</param>
    Public Shared Function ControlToHTML(ByVal Control As System.Web.UI.Control) As String
        Dim sHTML As String = String.Empty
        Dim oTextWriter As New System.IO.StringWriter()
        Dim oHTMLWriter As New System.Web.UI.HtmlTextWriter(oTextWriter)

        If Control.Page IsNot Nothing Then
            If TypeOf Control.Page Is TBBasePage Then
                DirectCast(Control.Page, TBActionPage).IsVerifyRender = False
            End If
        End If

        Control.RenderControl(oHTMLWriter)
        sHTML = oTextWriter.ToString()
        Return sHTML
    End Function