2014-01-30 2 views
1

jQuery TimeAgo 플러그인을 사용하기 위해 abbr 태그를 렌더링하는 간단한 컨트롤을 구현했습니다.사용자 정의 BoundField가 컨트롤을 잃습니다.

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으로 추상화 한 다음 DateTime 값이 포함 된 DataField의 이름을 전달하기 만하면됩니다. 충분히 간단하고 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도 ScriptManagers도 없습니다.

this 답이없는 질문은 물론 other 질문을 찾았습니다. 내 경우에는 결코 호출되지 않는 ExtractValuesFromCell 메서드를 무시해야한다고 나와 있습니다. 여기가 DataBind 이벤트 처리기에없는 컨트롤을 추가하지만 경우 오히려에서 InitializeDataCell 자체가 here을 제안하는 것이

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 모음입니다 (결과적으로, 제어에게 ID를 부여하고 FindControl을 사용하려고하면 null이 반환되지 않습니다. 분명히 DataBind 이벤트는 포스트 백에서 호출되지 않지만 라이프 사이클의이 단계에서 ViewState이 활성화되어 있으면 컨트롤이 포스트 백에서 유지 될 것으로 예상됩니다.

모든 포인터가 크게 감사하겠습니다. 미리 감사드립니다.

답변

0

비트가 기한이되었지만 누군가에게 도움이 될 경우 디 컴파일러 (DotPeek)를 실행하고 InitializeDataCell을 호출 할 때 기본 컨트롤이 수행 한 작업을 분석하여 해결했습니다. 이 메서드는 protected이고 다소 초기화 된 후에 메서드 InitializeCell에서 차례로 호출됩니다. 또한 DataBinding 이벤트에 OnDataBindField 메서드를 구독해야합니다. OnDataBindField에 대한 추가 검사 결과이 메서드는 TableCellText 속성을 설정하는 책임이 있음이 밝혀 졌으므로 다시 게시 한 후 날짜가 표시된 문자열 만 남았습니다.

나는 InitializeCell에 초기화 방법을 변경하고 다음과 같이 (해당 기본 대응을 호출하지 않고) OnDataBindField를 오버라이드 :

노트 : BoundField.OnDataBindFieldmsdn documentation 지금이 쪽지를 포함

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 클래스를 확장하면이 메서드를 재정의하여 사용자 지정 바인딩 루틴을 수행 할 수 있습니다.

관련 문제