當自訂控制項為輸入型控制項(如 TextBox、DropDownList、自訂編輯器)時,使用者輸入的值會隨表單回傳至伺服器。控制項必須實作 IPostBackDataHandler 介面,才能:
NameValueCollection) 讀取自己的值。TextChanged 等資料變更事件。public interface IPostBackDataHandler
{
// 從回傳資料載入控制項值
// 回傳 true 表示資料已變更,需引發 RaisePostDataChangedEvent
bool LoadPostData(string postDataKey, NameValueCollection postCollection);
// 資料確認變更後引發,通常在此觸發 TextChanged 等事件
void RaisePostDataChangedEvent();
}
頁面框架依 UniqueID 在回傳集合中尋找對應值。控制項必須在渲染時將 name 設為 UniqueID:
protected override void Render(HtmlTextWriter writer)
{
writer.AddAttribute(HtmlTextWriterAttribute.Name, UniqueID);
writer.AddAttribute(HtmlTextWriterAttribute.Id, ClientID);
writer.AddAttribute(HtmlTextWriterAttribute.Type, "text");
writer.AddAttribute(HtmlTextWriterAttribute.Value, Text); // 目前值
writer.RenderBeginTag(HtmlTextWriterTag.Input);
writer.RenderEndTag();
}
public virtual bool LoadPostData(string postDataKey, NameValueCollection postCollection)
{
string postedValue = postCollection[postDataKey]; // 使用者輸入的新值
string currentValue = Text; // 目前控制項值 (ViewState 還原後)
if (currentValue != postedValue)
{
Text = postedValue; // 更新控制項值
return true; // 標記資料已變更
}
return false; // 資料未變更
}
public event EventHandler TextChanged;
public virtual void RaisePostDataChangedEvent()
{
OnTextChanged(EventArgs.Empty);
}
protected virtual void OnTextChanged(EventArgs e)
{
if (TextChanged != null) TextChanged(this, e);
}
[ToolboxData("<{0}:CustomTextBox runat=server></{0}:CustomTextBox>")]
public class CustomTextBox : WebControl, IPostBackDataHandler
{
public string Text
{
get { object o = ViewState["Text"]; return o == null ? string.Empty : (string)o; }
set { ViewState["Text"] = value; }
}
public event EventHandler TextChanged;
protected override void Render(HtmlTextWriter writer)
{
writer.AddAttribute(HtmlTextWriterAttribute.Name, UniqueID);
writer.AddAttribute(HtmlTextWriterAttribute.Id, ClientID);
writer.AddAttribute(HtmlTextWriterAttribute.Type, "text");
writer.AddAttribute(HtmlTextWriterAttribute.Value, Text);
// 可加入 style、class、maxlength 等
writer.RenderBeginTag(HtmlTextWriterTag.Input);
writer.RenderEndTag();
}
public virtual bool LoadPostData(string postDataKey, NameValueCollection postCollection)
{
string posted = postCollection[postDataKey];
if (Text != posted)
{
Text = posted;
return true;
}
return false;
}
public virtual void RaisePostDataChangedEvent()
{
OnTextChanged(EventArgs.Empty);
}
protected virtual void OnTextChanged(EventArgs e)
{
if (TextChanged != null) TextChanged(this, e);
}
}
NameValueCollection 包含所有 name=value。IPostBackDataHandler 的控制項。LoadPostData(UniqueID, postCollection)。true,將控制項加入變更清單。Load 階段結束後,依序呼叫變更清單中控制項的 RaisePostDataChangedEvent()。TextChanged 等事件,開發者在事件處理常式中回應資料變更。IPostBackDataHandler 同時實作 IValidator 或搭配 ValidationPropertyAttribute,整合驗證架構。AutoPostBack="true" 並在 LoadPostData 偵測變更時呼叫 Page.ClientScript.GetPostBackEventReference(this, "") 觸發回傳(需渲染對應 __doPostBack 腳本)。| 錯誤 | 原因 | 修正 |
|---|---|---|
| LoadPostData 從未被呼叫 | 渲染的 name 屬性不是 UniqueID | 確保 Render 寫入 writer.AddAttribute("name", UniqueID) |
| TextChanged 事件不觸發 | LoadPostData 未回傳 true、或未實作 RaisePostDataChangedEvent | 比較邏輯正確、回傳 true、呼叫 OnTextChanged |
| 值在回傳後消失 | 未將 postedValue 指派給 Text 屬性 (ViewState) | LoadPostData 內 Text = postedValue |
| 多個同類控制項值混淆 | UniqueID 衝突 (未實作 INamingContainer) | 父控制項實作 INamingContainer 或繼承 CompositeControl |
IPostBackDataHandler 是 ASP.NET 伺服器控制項處理回傳輸入資料的標準協定。掌握「正確 name 屬性 → LoadPostData 比較新舊值 → RaisePostDataChangedEvent 引發事件」三步驟,即可打造功能完整、整合驗證架構、支援自動回傳的專業輸入型控制項。