在运行时动态绑定到自定义业务对象

Mar*_*ker 6 c# asp.net data-binding webforms

我正在开发一个Web窗体项目,它将Sql查询的结果加载到DataTable中.

这些DataTable被传递到前端,我们将它们绑定到Repeater Web控件.

这非常有效.但是,现在我们想绑定到我们自己的自定义类而不是DataTable.不幸的是,我认为明显的答案是行不通的(IDictionary<string, object>在我们班上实施).

我们需要将Eval绑定到Datum而不为每个绑定创建具体属性?显然,DataRow不必具体实现我们绑定的每个属性.所以,不知何故,似乎Eval能够在DataRow上按名称查找属性值.

这是自定义类

public class Datum: IDictionary<string, object>
{
    private Dictionary<string, object> _entries;

    public Datum()
    {
        _entries = new Dictionary<string, object>();
    }

    public object this[string s]
    {
        get
        {
            return this._entries[s];
        }
    }

    ...
}
Run Code Online (Sandbox Code Playgroud)

这是在aspx.cs文件中设置DataSource的位置

rptTags.DataSource = new[] { new Datum { {"Count", 1} }, new Datum { {"Count", 2 } };
Run Code Online (Sandbox Code Playgroud)

这是aspx文件中的绑定

<asp:Repeater ID="rptTags" runat="server">
    <ItemTemplate>
        <%# (int)Eval("Count") > 
    </ItemTemplate>
</asp:Repeater>
Run Code Online (Sandbox Code Playgroud)

使用上面的示例,我们得到一个错误,指出有问题的属性不存在,这是真的,但它也不存在于DataRow上.如何使它像System.Data.DataRow一样绑定?

Mar*_*ker 1

今天早上我以全新的眼光来到这里,花了几个小时使用 ILSpy 浏览 .Net Framework。我终于能够解决这个难题并实施一个可行的解决方案。我将列出我学到的与解决方案相关的内容,然后详细说明我的实现。

  • 当您将 DataTable 绑定到 Repeater 时,每个 RepeaterItem 不会像我预期的那样绑定到 DataRow,而是绑定到 DataRowView。这实际上并不重要,只是 DataRowView 实现了ICustomTypeDescriptor我们需要在类上实现的接口。
  • 尽管MSDN 文档说 Eval 方法使用反射来执行后期绑定,并且您的表达式必须计算为公共属性,但这根本不是事实。Eval 语句使用 ICustomTypeDescriptor 上的 GetProperties() 方法来计算表达式。

考虑到这一点,我必须采取以下步骤来创建我自己的自定义类型,我可以像 DataTable 一样动态绑定到该类型。

  1. 创建您自己的继承自 PropertyDescriptor 的自定义类。
  2. 实现 PropertyDescriptor 的所有抽象成员。对于动态绑定来说,最重要的是 GetValue()。您可以在此处定义如何从要绑定的类中获取值。
  3. 在您将绑定到的类上,继承自 CustomTypeDescriptor。这是一个实现 ICustomTypeDescriptor 的通用类。
  4. 重写 CustomTypeDescriptor 的 GetProperties() 方法,并为您希望能够绑定的每个值返回 PropertyDescriptor 列表(在步骤 1-2 中创建)。
  5. 确保您的 PropertyDescriptions 已设置其 Name 属性。这是 .Net 与您的 Eval 表达式进行比较的属性,以便确定绑定时使用哪个 PropertyDescription。
  6. 将 CustomTypeDescriptor 对象(在步骤 3-5 中创建)设置为 WebControl 的 DataSource 并使用 Eval() 动态绑定到它