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

时间:2012-02-14 22:06:30

标签: c# asp.net data-binding webforms

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

将这些DataTable传递到前端,我们将它们绑定到Repeater网络控件。

这很有效。但是,现在我们要绑定到我们自己的自定义类而不是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];
        }
    }

    ...
}

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

rptTags.DataSource = new[] { new Datum { {"Count", 1} }, new Datum { {"Count", 2 } };

这是aspx文件中的绑定

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

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

2 个答案:

答案 0 :(得分:1)

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

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

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

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

答案 1 :(得分:0)

可绑定的DataSource应实现IEnumerableIListSource

关于动态方面:请记住,数据绑定的部分魔力是使用反射进行的。