c# - 如何编写自定义模板字段类 DataControlField

标签 c# asp.net data-binding templatefield

我正在使用 GridView显示其中一个数据列的类型为 DateTimeOffset 的数据.为了以用户的时区显示日期和时间,我将用户的时区偏好保存到他或她的个人资料中(属性值键“TimezoneOffset”),并且在格式化日期和时间时需要访问它。

如果我要使用模板字段,那么我需要这样写:

<abbr class="datetimeoffset">
<%#
    ((DateTimeOffset)Eval("CreatedDate"))
    .ToOffset(new TimeSpan(-((Int32)Profile.GetPropertyValue("TimezoneOffset"))
                            .ToRepresentativeInRange(-12, 24), 0, 0)).ToString("f") %>
</abbr>

太复杂且不可重用。

我尝试添加 TimeSpan代码隐藏的属性(至少将其移出数据绑定(bind)表达式),但显然 View 的代码隐藏的属性在 <%# ... %> 中不可访问。 .

因此,我认为我需要编写自定义 DataControlField在用户的时区中格式化日期和时间。

我已经开始了:

public class DateTimeOffsetField : DataControlField
{
    private TimeSpan userOffsetTimeSpan;

    protected override DataControlField CreateField()
    {
        return new DateTimeOffsetField();
    }

    protected override void CopyProperties(DataControlField newField)
    {
        base.CopyProperties(newField);
        ((DateTimeOffsetField)newField).userOffsetTimeSpan = userOffsetTimeSpan;
    }

    public override bool Initialize(bool sortingEnabled, System.Web.UI.Control control)
    {
        bool ret = base.Initialize(sortingEnabled, control);
        int timezoneOffset = ((Int32)HttpContext.Current.Profile.GetPropertyValue("TimezoneOffset")).ToRepresentativeInRange(-12, 24);
        userOffsetTimeSpan = new TimeSpan(-timezoneOffset, 0, 0);
        return ret;
    }
}

但现在我卡住了。如何输出 HTML <abbr class="datetimeoffset"><%# ((DateTimeOffset)Eval("CreatedDate")).ToOffset(userOffsetTimeSpan).ToString("f") %></abbr>每个单元格?

编辑:我一直在阅读一篇标题为 Cutting Edge: Custom Data Control Fields 的文章.到目前为止,我已经添加了:

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

        if (cellType == DataControlCellType.DataCell)
        {
            InitializeDataCell(cell, rowState, rowIndex);
        }
    }

    protected virtual void InitializeDataCell(DataControlFieldCell cell, DataControlRowState rowState, int rowIndex)
    {
        System.Web.UI.Control control = cell;

        if (control != null && Visible)
        {
            control.DataBinding += new EventHandler(OnBindingField);
        }
    }

    protected virtual void OnBindingField(object sender, EventArgs e)
    {
        var target = (System.Web.UI.Control)sender;

        if (target is TableCell)
        {
            TableCell tc = (TableCell)target;
        }
    }

但是文章设置了 Text TableCell 的属性(property)例如,我想将部分 View 渲染到表格单元格中。这可能吗?

最佳答案

我想通了。这是我最终得到的结果:

// DateTimeOffsetField.cs
public class DateTimeOffsetField : BoundField
{
    private TimeSpan userOffsetTimeSpan;

    protected override DataControlField CreateField()
    {
        return new DateTimeOffsetField();
    }

    protected override void CopyProperties(DataControlField newField)
    {
        base.CopyProperties(newField);
        ((DateTimeOffsetField)newField).userOffsetTimeSpan = userOffsetTimeSpan;
    }

    public override bool Initialize(bool sortingEnabled, System.Web.UI.Control control)
    {
        bool ret = base.Initialize(sortingEnabled, control);
        int timezoneOffset = ((Int32)HttpContext.Current.Profile.GetPropertyValue("TimezoneOffset")).ToRepresentativeInRange(-12, 24);
        userOffsetTimeSpan = new TimeSpan(-timezoneOffset, 0, 0);
        return ret;
    }

    protected override void OnDataBindField(object sender, EventArgs e)
    {
        base.OnDataBindField(sender, e);

        var target = (Control)sender;

        if (target is TableCell)
        {
            var tc = (TableCell)target;
            var dataItem = DataBinder.GetDataItem(target.NamingContainer);
            var dateTimeOffset = (DateTimeOffset)DataBinder.GetPropertyValue(dataItem, DataField);
            tc.Controls.Add(new TimeagoDateTimeOffset { DateTimeOffset = dateTimeOffset.ToOffset(userOffsetTimeSpan) });
        }
    }
}

TimeagoDateTimeOffset.cs:

[DefaultProperty("DateTimeOffset")]
[ToolboxData("<{0}:TimeagoDateTimeOffset runat=server></{0}:TimeagoDateTimeOffset>")]
public class TimeagoDateTimeOffset : WebControl
{
    [Bindable(true)]
    [Category("Appearance")]
    [DefaultValue("")]
    [Localizable(true)]
    public DateTimeOffset DateTimeOffset
    {
        get { return (DateTimeOffset)ViewState["DateTimeOffset"]; }
        set { ViewState["DateTimeOffset"] = value; }
    }

    protected override void RenderContents(HtmlTextWriter writer)
    {
        writer.BeginRender();
        writer.AddAttribute(HtmlTextWriterAttribute.Class, "timeago", false);
        writer.AddAttribute(HtmlTextWriterAttribute.Title, DateTimeOffset.ToString("o"));
        writer.RenderBeginTag("abbr");
        writer.Write(DateTimeOffset.ToString("d"));
        writer.RenderEndTag();
        writer.EndRender();
    }
}

关于c# - 如何编写自定义模板字段类 DataControlField,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4769036/

相关文章:

c# - 使用 EF 7(核心)将实体绑定(bind)到 WPF 数据网格中

c# - ObservableCollection 和 INotifyPropertyChanged 的​​ WPF MVVM 问题

c# - 当我使用线程将内容打印到控制台时,为什么会产生奇怪的结果?

c# - 使用 ASP.NET Core Web API 在 Swashbuckle 6 (Swagger) 中重命名模型

c# - 使用 Linq 从嵌套集合中选择对象

ASP.NET 动态添加控件和页面生命周期

c# - Sitecore 语言嵌入多个站点

ASP.NET Core 2.1 API 缓存

wpf - 根据WPF中的TextBox Text属性启用/禁用按钮?

c# - 为每个后面的代码添加附加属性的数据绑定(bind)