簡體   English   中英

自定義BoundField失去對PostBack的控制

[英]Custom BoundField loses control on PostBack

我已經實現了一個簡單的控件,該控件呈現abbr標簽,以便使用jQuery TimeAgo插件。

public class TimeAgoControl : System.Web.UI.WebControls.WebControl
{
    [Bindable(true)]
    [DefaultValue(null)]
    public string Iso8601Timestamp
    {
        get { return (string)ViewState["Iso8601Timestamp"]; }
        set { ViewState["Iso8601Timestamp"] = value; }
    }

    [Bindable(true)]
    [DefaultValue(null)]
    public override string ToolTip
    {
        get { return (string)ViewState["ToolTip"]; }
        set { ViewState["ToolTip"] = value; }
    }

    public override void RenderControl(HtmlTextWriter writer)
    {
        writer.AddAttribute("class", "timeago");
        writer.AddAttribute("title", Iso8601Timestamp);
        writer.RenderBeginTag("abbr");
        RenderContents(writer);
        writer.RenderEndTag();
    }

    protected override void RenderContents(HtmlTextWriter writer)
    {
        writer.WriteEncodedText(ToolTip);
    }
}

這很好。 我可以在GridView TemplateField使用上面的控件,它也可以正常工作:

<asp:TemplateField>
    <ItemTemplate>
        <my:TimeAgoControl runat="server" Iso8601Timestamp='<%# Item.LastImportDate.ToString("s") %>' 
                           ToolTip='<%# Item.LastImportDate.ToString("f") %>' />
    </ItemTemplate>
</asp:TemplateField>

自然,我不想每次都想在GridView中使用控件時都輸入所有上述內容,因此我想將上述邏輯抽象到自定義的BoundField ,在其中我只需傳遞包含以下內容的DataField的名稱要呈現的DateTime值。 很簡單,從System.Web.UI.WebControls.BoundField擴展並重寫InitializeDataCell方法,向其中的DataControlFieldCell添加控件,並將處理程序附加到DataBinding事件。 它可以工作並生成正確的標記:

<td><abbr class="timeago" title="Wednesday, January 29, 2014 16:17">about 23 hours ago</abbr></td>

但是當頁面執行回發時,控件消失了,剩下的就是

<td>29.01.2014 16:17:17</td>

請注意, 該頁面不使用Ajax功能 :它不包含UpdatePanels或ScriptManager。

我已經進行了相當多的研究,找到了這個未解決的問題以及另一個問題,該問題指出必須覆蓋ExtractValuesFromCell方法,在我的情況下,此方法從未調用過。 這是我的實現

public class TimeAgoBoundField : System.Web.UI.WebControls.BoundField
{
    protected override void InitializeDataCell(System.Web.UI.WebControls.DataControlFieldCell cell, System.Web.UI.WebControls.DataControlRowState rowState)
    {
        base.InitializeDataCell(cell, rowState);

        cell.Controls.Add(new TimeAgoControl());

        cell.DataBinding += (sender, e) =>
        {
            var c = (DataControlFieldCell)sender;
            //how do I get the TimeAgoControl within this scope? c.Controls.Count is 0
            var dateTimeValue = (DateTime?)DataBinder.GetPropertyValue(DataBinder.GetDataItem(c.NamingContainer), this.DataField);
            c.Controls.Add(new TimeAgoControl
            {
                Iso8601Timestamp = dateTimeValue.HasValue ? dateTimeValue.Value.ToLocalTime().ToString("s") : this.NullDisplayText,
                ToolTip = DateTimeValue.HasValue ? dateTimeValue.Value.ToLocalTime().ToString("f") : this.NullDisplayText
            });                
        };
    }
}

請注意,如果不按此處建議的那樣將Controls添加到DataBind事件處理程序中,而是將其添加到InitializeDataCell本身中,則Controls集合為 (因此,為控件提供ID並嘗試使用FindControl失敗,則返回null)。 顯然,在回發時不會調用DataBind事件,但是鑒於ViewState在生命周期的此階段處於活動狀態,所以我希望控件在回發時能夠持久存在。

任何指針將不勝感激。 提前致謝。

有點過期了,但是如果這對某人有所幫助,我通過啟動反編譯器( DotPeek )並分析基本控件在調用InitializeDataCell時的工作來解決此問題。 事實證明,此方法是protected ,而是在進行一些初始化之后從public方法InitializeCell依次調用。 此外,它負責將OnDataBindField方法預訂到DataBinding事件。 進一步檢查OnDataBindField發現,此方法負責設置TableCellText屬性,因此為什么在回發后僅留下日期的字符串表示形式。

我將Initialize方法更改為InitializeCell並覆蓋了OnDataBindField (不調用其基本對應項),如下所示:

public class TimeAgoBoundField : System.Web.UI.WebControls.BoundField
{
    public override bool ReadOnly
    {
        get { return true; }
    }

    public override void InitializeCell(DataControlFieldCell cell, DataControlCellType cellType, DataControlRowState rowState, int rowIndex)
    {
        base.InitializeCell(cell, cellType, rowState, rowIndex);

        if (cellType == DataControlCellType.DataCell)
        {
            cell.Controls.Add(new TimeAgoControl());
        }
    }

    protected override void OnDataBindField(object sender, EventArgs e)
    {
        if (sender is TableCell)
        {
            var cell = (TableCell)sender;
            var cellValue = this.GetValue(cell.NamingContainer);

            if (cellValue != null)
            {
                var timeAgoControl = (TimeAgoControl) cell.Controls[0];
                var dateTimeValue = (DateTime) cellValue;
                var utcDateTime = dateTimeValue.Kind != DateTimeKind.Utc ? dateTimeValue.ToUniversalTime() : dateTimeValue;
                timeAgoControl.ISO8601Timestamp = utcDateTime.ToString("s") + "Z";
            }
            else if (this.NullDisplayText != null)
            {
                cell.Text = this.NullDisplayText;
            }
        }
    }
}

BoundField.OnDataBindFieldmsdn文檔現在包含此注釋:

對繼承者的說明擴展BoundField類時,可以重寫此方法以執行自定義綁定例程。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM