1

KB-Controls.AddAt可能破壞ViewState

 2 years ago
source link: https://blog.darkthread.net/blog/controls-addat-will-spoil-viewstate/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
KB-Controls.AddAt可能破壞ViewState-黑暗執行緒

前些時候,為了解決MatserPage下元件的ClientID會被加註Prefix的問題,我寫了一段彈性化找尋ClientID的Javascript Function取代document.getElementById(),並且為了確保WebControl在產生HTML的同時就可以插入Javascript呼叫它,我利用Page.Form.Control.AddAt(0, Literal)的技巧讓它插隊顯示在最前方。

今天同事回報,這種插隊法會讓下拉選單的選項在PostBack後掉光光,我懷疑是ViewState解析順序被破壞導致,於是寫了以下的Code驗證。以下的寫法,只要呼叫了Page.Form.Controls.AddAt(0, ...), 在按下Button1後,下拉選項就會消失。

排版顯示純文字
<%@ Page Language="C#" AutoEventWireup="true" %>
<html>
<head runat="server">
    <title>ViewState Is Missing</title>
</head>
<body>
    <form id="form1" runat="server">
    <script type="text/C#" runat="server">
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                DropDownList1.Items.Add("Item1");
                DropDownList1.Items.Add("Item2");
                DropDownList1.Items.Add("Item3");
            }
            Literal ltr = new Literal();
            ltr.Text =
                "<script type=\"text/javascript\">function blah() { }</"
                + "script>";
            Page.Form.Controls.AddAt(0, ltr);
        }
        protected void Button1_Click(object sender, EventArgs e)
        {
        }     
    </script>
    <div>
        <asp:DropDownList ID="DropDownList1" runat="server">
        </asp:DropDownList>
        <asp:Button ID="Button1" runat="server" Text="Button" onclick="Button1_Click" />
    </div>
    </form>
</body>
</html>

微軟有篇文章提到這一點:

When adding a dynamic control c to some parent control p based on some condition (that is, when not loading them on each and every page visit), you need to make sure that you add c to the end of p's Controls collection.

所以囉! 用Controls.AddAt真的挺危險的在Page_Load中用Controls.AddAt真的挺危險的,但我又這麼在意要把<script>擺到最前面,怎麼辦?

改成Page.Header.Controls.Add(...)吧! 搞定收工!

Update @ 2007-01-04
網友大估找到更好的解法,將Control.AddAt()移至Page_Init()事件就可以了,這個測試結果也解釋了Control.AddAt攪亂ViewState的理由:
依Control Execution Lifecyvle中Event的順序,Load被夾在Load View State與Save State之間,因此在Load加入Contorl,會發生Save State時Control存在,下次PostBack Load State時卻Control卻還沒生出來的情況,因此造成了View State錯亂。嚴格來說,新增Control放在Init事件,會比放在Load中好。謝謝大估提供的建議!

Update 2008-01-19
強化版搜尋範圍擴及UserControl,說明在此


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK