自問對如何把玩Dynamic Web Control,Page Life Cycle是怎樣,如何重構Controls和ViewState都很了解。
但奈何今天敗在一個CheckBox Control下,花了我半天才搞定,所以在Blog上做一個記錄和分享。
而遇到的問題就是,
在同一個Form內,PostBack後,所有動態Control都存取都正常,唯獨是任何CheckBox Controls的Checked屬性一直都是False。
搞了一段時間後,我決定由最原始的方式 Request.Form 的方式,去找出問題在那裡。
或者這樣說太抽象,先看看Source Code和Screen Shot。
Markup 方面很簡單,一個Button,一個PlaceHolder。
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="test.aspx.cs" Inherits="test" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title></title>
</head>
<body style="font-family: Tahoma; font-size: 11px;">
<form id="form1" runat="server">
<div>
<asp:Button ID="btnAdd" runat="server" Text="Add CheckBox" OnClick="btnAdd_Click" />
<asp:PlaceHolder ID="PlaceHolder1" runat="server" />
</div>
</form>
</body>
</html>
再來是Source部份,留意Line:62 & 63 :using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class test : System.Web.UI.Page
{
protected int NumberOfControls
{
get { return (int)ViewState["ControlCount"]; }
set { ViewState["ControlCount"] = value; }
}
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
NumberOfControls = 0;
else
RecreateControls();
}
protected void btnAdd_Click(object sender, EventArgs e)
{
CreateControls(this.NumberOfControls);
this.NumberOfControls++;
}
private void CreateControls(int i)
{
CheckBox chk = new CheckBox();
chk.ID = "chk" + i.ToString();
Label lbl = new Label { ID = "lbl" + i.ToString(), Text = "
Index : " + i.ToString() };
PlaceHolder1.Controls.Add(lbl);
PlaceHolder1.Controls.Add(chk);
PlaceHolder1.Controls.Add(new Literal { Text = "
" });
}
private void RecreateControls()
{
int count = this.NumberOfControls;
for (int i = 0; i < count; i++)
CreateControls(i);
int idx = 0;
for (int x = 0; x < PlaceHolder1.Controls.Count; x++)
{
Control ctl = PlaceHolder1.Controls[x];
if (ctl is Label)
{
Response.Write(((Label)ctl).Text);
}
else if (ctl is CheckBox)
{
Response.Write(" Checked : "
+ ((CheckBox)ctl).Checked.ToString() + " | "
+ Request.Form["chk" + idx.ToString()] + "
");
idx++;
}
}
}
}
得出來的結果如下圖 :

使用((CheckBox)ctl).Checked.ToString()輸出是False,但Request.Form找取Value卻是"on",最奇怪就是用IE的Deveper Tool看一看文件,明明真的有CHECKED="checked",換句話說,ASP.NET的CheckBox Control在勾選或取消勾選雖然會變更Client-Side Value和Checked屬性,但不會更改Control States的Checked的屬性,這就是問題的根源,於是我立即想起沒有PostBack的原故。
那如何解決呢? 很簡單,就是把CheckBox的AutoPostBack設成True,再在CheckedChanged的Event加上Event Handler就可以了。

整理後的Source :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class test : System.Web.UI.Page
{
protected int NumberOfControls
{
get { return (int)ViewState["ControlCount"]; }
set { ViewState["ControlCount"] = value; }
}
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
NumberOfControls = 0;
else
RecreateControls();
}
protected void btnAdd_Click(object sender, EventArgs e)
{
CreateControls(this.NumberOfControls);
this.NumberOfControls++;
}
private void CreateControls(int i)
{
CheckBox chk = new CheckBox();
chk.ID = "chk" + i.ToString();
chk.AutoPostBack = true;
chk.CheckedChanged += CheckedChanged;
Label lbl = new Label { ID = "lbl" + i.ToString(), Text = "
Index : " + i.ToString() };
PlaceHolder1.Controls.Add(lbl);
PlaceHolder1.Controls.Add(chk);
PlaceHolder1.Controls.Add(new Literal { Text = "
" });
}
private void CheckedChanged(Object sender, EventArgs e)
{
}
private void RecreateControls()
{
int count = this.NumberOfControls;
for (int i = 0; i < count; i++)
CreateControls(i);
int idx = 0;
for (int x = 0; x < PlaceHolder1.Controls.Count; x++)
{
Control ctl = PlaceHolder1.Controls[x];
if (ctl is Label)
{
Response.Write(((Label)ctl).Text);
}
else if (ctl is CheckBox)
{
Response.Write(" Checked : "
+ ((CheckBox)ctl).Checked.ToString() + " | "
+ Request.Form["chk" + idx.ToString()] + "
");
idx++;
}
}
}
}
沒有留言:
發佈留言