Thursday, January 03, 2008 - 文章

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,說明在此

101煙火秀的另類觀點

凡事有光明面,就會有黑暗面...

101的跨年煙火秀已然成為北台灣的年度盛事之一,相信大家就算沒到現場,從新聞上也都目睹了今年188秒的絢爛花火、還看到連建築物都得呼口號"愛台灣"的美妙奇蹟(我很認同利用難得機會Show出台灣爭取國際曝光的用心,但加上了"愛"就流於矯情)。

電視鏡頭下的煙火發發鮮明、精彩奪目,幾位同事朋友不畏人潮凶險,帶著裝備早早佔位,也都獵回了不少好照片(1, 2, 3)。

午夜11點,分明已被烙上"限居家使用"的中年人,忽然興起了一絲不安分,不想如往年只在政大河濱看1/3根的花火雞毛撢,帶著一家大小驅車往母校台科大衝。

接近目的地時已11點半,可以望見101的觀景點早就併排停滿了車,站滿了人。等開到大老遠有地方可停,只餘下10分鐘不到找地方。胡亂挑了個人不算多的巷子口,已是熄燈倒數時刻。

5, 4, 3, 2, 1! 哇~~~ 啊.... 呃.... 哦....

除了前幾波還看得到煙火,後面只看一根棉花糖不時滲出火光。新聞說台北冬天吹東風,站在南邊怎會落得如此下場? (後來看新聞說,當時吹東北風,好樣的!) 188秒皮影戲結束,全部的人又像逃難一樣要離開現場,花了半個多小時才塞回家。

老天爺,我知錯了,明年我會乖乖看1/3根就算了。
(如果明年還有的話。據說今年是101最後一次放煙火,但我持保留態度,這是台灣少數可以躍上國際版面的機會,不應該只從101自身的成本回收或施工難易考量。不過,今年在電視上看到香港的跨年煙火,走的不是101數大便是美的路子,而是巧妙設計了由不同方向、依序放出顏色不同的煙火,像是在看一場動畫表演,故事性十足。也許未來101的煙火也可以考量改走精緻化、巧思化的風格,未必要砸大錢也能博得滿堂彩。)

搜尋

Go

<January 2008>
SunMonTueWedThuFriSat
303112345
6789101112
13141516171819
20212223242526
272829303112
3456789
 
RSS
【工商服務】
最新回應

Tags 分類檢視
關於作者

一個醉心技術又酷愛分享的Coding魔人,十年的IT職場生涯,寫過系統、管過專案, 也帶過團隊,最後還是無怨無悔地選擇了技術鑽研這條路,近年來則以做一個"有為的中年人"自許。

文章典藏
其他功能

這個部落格


BlogLook Score and Rank

Syndication