使用 ASP.NET Dynamic Data 的 DynamicField / DynamicControl 時,PostBack 會拋出:
The DynamicControl/DynamicField needs to exist inside a data control that is bound to a data source that supports Dynamic Data.
中文:綁定到支援動態資料之資料來源的資料控制項內,必須存在 DynamicControl/DynamicField。
PostBack 事件流程與初始載入不同。資料控制項 (DetailsView, GridView, ListView 等) 在狀態載入階段會初始化所有 Fields/Columns,但此時資料來源尚未繫結,導致找不到 MetaTable,進而拋出例外。若在 InitComplete 前完成資料繫結可避免,但許多專案習慣在 Load 階段繫結,改動成本高。
自訂 DdField、DdControl,在初始化前檢查 FindMetaTable() 是否為 null,若無則略過初始化,避免拋出例外。
namespace Common
{
///
/// 修正 DynamicField PostBack 找不到 MetaTable 的例外
///
public class DdField : DynamicField
{
public override void InitializeCell(
DataControlFieldCell cell,
DataControlCellType cellType,
DataControlRowState rowState,
int rowIndex)
{
// HACK: 若找不到 MetaTable,直接返回,不進行後續初始化
if (base.Control.FindMetaTable() == null) return;
base.InitializeCell(cell, cellType, rowState, rowIndex);
}
}
}
namespace Common
{
///
/// 修正 DynamicControl PostBack 找不到 MetaTable 的例外
///
public class DdControl : DynamicControl
{
protected override void OnInit(EventArgs e)
{
// HACK: 僅在找到 MetaTable 時才呼叫基底 OnInit
if (this.FindMetaTable() != null) base.OnInit(e);
}
}
}
<configuration>
<system.web>
<pages>
<controls>
<!-- 假設編譯後為 Common.dll -->
<add tagPrefix="asp" namespace="Common" assembly="Common" />
</controls>
</pages>
</system.web>
</configuration>
<DetailsView ID="DetailsView1" runat="server" AutoGenerateRows="False">
<Fields>
<asp:DdField DataField="Name" />
<asp:DdField DataField="Email" />
</Fields>
</DetailsView>
| 類別 | 覆寫方法 | 攔截時機 |
|---|---|---|
DdField | InitializeCell | 資料控制項建立儲存格時,檢查 MetaTable 是否存在 |
DdControl | OnInit | 控制項 Init 階段,檢查 MetaTable 是否存在 |
若 FindMetaTable() == null 表示資料來源尚未繫結或不支援 Dynamic Data,直接跳過初始化,避免拋出例外。後續資料繫結完成後,控制項會重新經歷生命週期並正常運作。
Eval/Bind 語法,開發體驗無差異。作者近期大量使用 DynamicFieldTemplates 開發應用,對此類問題深有體會。若發現 Bug 請來信回報,持續維護中。