2011/03/23

用 RadioButtonList 當 UpdatePanel Trigger 時無法正常觸發非同步更新之解法

ASP.NET的RadioButtonList,預設不會作PostBack,但是如果用上AutoPostBack又會跟Page_Load中的IsPostBack有相衝的地方。
所以可以採用下列的方式,就可以讓RadioButtonList作PostBack了。


用 RadioButtonList 當 UpdatePanel Trigger 時無法正常觸發非同步更新之解法
原始問題出處。這問題印象中我好像也碰過幾次,但一直沒有去深究原因,因為要解決並不困難 (容後說明),但今天再度看到有人提問,索性好好了解一下始末。

首先依照原發問者提供的頁面配置及程式碼重現案發現場:

aspx部份

<form id="form1" runat="server">

<div>

<ajaxToolkit:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">

</ajaxToolkit:ToolkitScriptManager>

<asp:RadioButtonList ID="rblType" runat="server" OnSelectedIndexChanged="rblType_SelectedIndexChanged"

RepeatDirection="Horizontal" AutoPostBack="true">

<asp:ListItem Value="I" Selected="True">新增新案</asp:ListItem>

<asp:ListItem Value="U">修改新案</asp:ListItem>

<asp:ListItem Value="O">舊案續約</asp:ListItem>

</asp:RadioButtonList>

<asp:UpdatePanel ID="upl" runat="server" UpdateMode="Conditional" ChildrenAsTriggers="False">

<ContentTemplate>

<asp:Panel ID="pnl" runat="server" Visible="false">

<asp:DropDownList ID="ddlAmtYear" runat="server" Width="320" Height="23" />

</asp:Panel>

</ContentTemplate>

<Triggers>

<asp:AsyncPostBackTrigger ControlID="rblType" EventName="SelectedIndexChanged" />

</Triggers>

</asp:UpdatePanel>

</div>

</form>


CS部份

protected void rblType_SelectedIndexChanged(object sender, EventArgs e)

{

if (rblType.SelectedValue == "I")

pnl.Visible = false;

else

pnl.Visible = true;

}



程式很單純,判斷 RadioButtonList 的選取值以非同步更新的方式切換 Panel 隱藏 / 顯示,但執行起來果真如發問者所說,RadioButtonList.SelectedIndexChanged 初次引發時,會觸發 UpdatePanel 更新,但接下來再點回去預設選項則不會觸發非同步更新…。

身為一個網頁開發人員,遇到網頁執行結果不如預期時,把網頁開起來檢視原始碼是常用的除錯技巧,不一會兒工夫,看到一個不尋常的地方:

radiobuttonlist_html


如上圖所示,RadioButtonList 預設選取的選項,在 Render 成 HTML 後少了 "onclick=javascript:setTimeout('__doPostBack(\'rblType$0\',\'\')" 這一段,這是設定 RadioButtonList.AutoPostBack 屬性為 true 時,會自動幫每一個選項加上去的,目的是在點選任一選項之後送回 Server 端處理,要命的是預設選取的那一個選項不會加...。

知道原因之後,可以來想怎麼解決了。開頭說過我曾遇過同樣的問題,沒有深究的原因是這問題沒有耽擱到太多時間,所以一直不以為意,其實只要把 RadioButtonList 放到 UpdatePanel 裡面就不會有這樣的問題了,這是比較建議的做法。但真的不想把 RadioButtonList 丟到 UpdatePanel 裡的話也是有解,但要動點手腳,既然預設選取的選項會少指令碼,那我們就手動補上去,比較恰當的時機點是在 RadioButtonList.PreRender 事件處理:

protected void rblType_PreRender(object sender, EventArgs e)

{

RadioButtonList radioButtonList = ((RadioButtonList)sender);



foreach (ListItem li in radioButtonList.Items)

{

// 預設選取的選項加上 onclick 事件指令碼

if (li.Selected)

{

li.Attributes.Add("onclick",

String.Format("javascript:setTimeout('__doPostBack(\\'{0}${1}\\',\\'\\')', 0)",

radioButtonList.UniqueID,

radioButtonList.Items.IndexOf(li)));

}

}

}

在開始上傳前檢查檔案大小(IE僅能檢查圖片)

這篇其實不是單純只能檢查圖片而已,連一般檔案都可以檢查。目前還沒在Safari瀏覽器上實驗過就是了。
2011/3/24 04:18 剛確認了IE如果是圖片以外的檔案,確實要用額外的方式處理。

[JavaScript] 在開始上傳前檢查圖片檔案大小
最近有此功能需求,因此查了些相關的資料,最後在不使用 Flash 及 ActiveX 等技術的情況下,只用JavaScript完成了多瀏覽器的功能實作,在此分享。

目前已測試過的瀏覽器:IE 6 , IE 7 , IE 8 , Firefox , Chrome;另外 Firefox 與 Chrome 的版本須為支援 Html 5 的版本。


以下為 HTML (此部分與 Bryan(不來ㄣ)大大的版本相同 ):
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=big5">
    <title>上傳</title>
</head>
<body>
    <form action="upload.asp" method="POST" name="FileForm" enctype="multipart/form-data">
    <div align="center">
        圖片:
    <input type="file" name="file1" size="20" id="file1" />
    <input type="button" value="確定上傳" onclick="checkFile()" /></div>
    </form>
</body>
</html>


以下為 JavaScript:
<script src="http://code.jquery.com/jquery-1.4.2.min.js" type="text/javascript"></script>
<script language="JavaScript" type="text/javascript">
    var fileSize = 0; //檔案大小
    var SizeLimit = 1024; //上傳上限,單位:byte
    function checkFile() {
    var f = document.getElementById("file1");
    //FOR IE
    if ($.browser.msie) {
            var img = new Image();
            img.onload = checkSize;
            img.src = f.value;
        }
        //FOR Firefox,Chrome
        else {
            fileSize = f.files.item(0).size;
            checkSize();
        }
    }
    //檢查檔案大小
    function checkSize() {
        //FOR IE FIX
        if ($.browser.msie) {
            fileSize = this.fileSize;
        }
        if (fileSize > SizeLimit) {
            Message((fileSize / 1024).toPrecision(4), (SizeLimit / 1024).toPrecision(2));
        } else {
            document.FileForm.submit();
        }
    }
    function Message(file, limit) {
        var msg = "您所選擇的檔案大小為 " + file + " kB\n已超過上傳上限 " + limit + " kB\n不允許上傳!"
        alert(msg);
    }
</script>

參考資料:
topcat 姍舞之間的極度凝聚 - [轉貼]上傳檔案前,JavaScript檢查檔案格式、大小:http://www.dotblogs.com.tw/topcat/archive/2009/02/20/7250.aspx (Bryan(不來ㄣ)大大的版本 – For IE)
簡單過生活 - Check 上傳檔案大小:http://iammic.pixnet.net/blog/post/11866034 (iammic大大的版本 – For IE[ActiveX] & Firefox , Chrome)

2010/09/22 更新:
在 o 大大的指正後,將標題略為修改為針對圖片檔案的上傳之檔案大小的檢查,以避免因標題誤導了想找資料的訪客。
另外,在支援 HTML 5 的 Firefox 與 Chrome 的瀏覽器版本上,是可正確抓到各類型檔案大小的;而 IE 瀏覽器仍須透過 Flash 或 ActiveX 等技術才能取得圖片類型以外的檔案大小,在此作以上更正。