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

发布于 2025-01-05 08:17:31 字数 1517 浏览 3 评论 0原文

我正在开发一个 Web 表单 项目,该项目将 Sql 查询的结果加载到 数据表

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

这很好用。但是,现在我们希望绑定到我们自己的自定义类而不是 DataTable。不幸的是,我认为显而易见的答案不起作用(在我们的类上实现 IDictionary)。

在不为每个绑定创建具体属性的情况下,我们需要什么才能将 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一样绑定?

I am working on a Web Forms project that loads the results of Sql queries into DataTables.

These DataTables are passed up to the front-end where we bind them to a Repeater web control.

This works great. However, now we'd like to bind to our own custom classes instead of a DataTable. Unfortunately, what I thought was the obvious answer didn't work (implementing IDictionary<string, object> on our class).

What do we need to have Eval bind to Datum without creating a concrete property for every binding? Clearly DataRow doesn't have to concretely implement every property we bind. So, somehow it seems that Eval is able to look up the property values by name on DataRow.

Here is the custom class

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];
        }
    }

    ...
}

Here is where the DataSource is set in the aspx.cs file

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

And here is the binding in the aspx file

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

Using the above example we get an error saying that the property in question doesn't exist, which is true, but it doesn't exist on DataRow either. How can I make it bind like System.Data.DataRow?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

最终幸福 2025-01-12 08:17:31

今天早上我以全新的眼光来到这里,花了几个小时使用 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() 动态绑定到它

I came in this morning with fresh eyes and spent several hours going through the .Net Framework with ILSpy. I was finally able to figure this puzzle out and implement a working solution. I'll list things I learned that are pertinent to the solution and then detail my implementation.

  • When you bind a DataTable to a Repeater each RepeaterItem doesn't bind to a DataRow, like I expected, but to a DataRowView. This really isn't important except that DataRowView implements the ICustomTypeDescriptor interface which is what we need to implement on our class.
  • Even though the MSDN documentation says the Eval method uses reflection to perform late-binding and your expression must evaluate to a public property this is simply not true. The Eval statement uses the GetProperties() method on ICustomTypeDescriptor to evaluate your expression.

With that in mind here are the steps I had to take to create my own custom type that I could dynamically bind to just like DataTable.

  1. Create your own custom class that inherits from PropertyDescriptor.
  2. Implement all of PropertyDescriptor's abstract members. For dynamic binding the most important one is GetValue(). This is where you define how to get the values from the class you are binding to.
  3. On the class you will be binding to, inherit from CustomTypeDescriptor. This is a generic class that implements ICustomTypeDescriptor.
  4. Override the GetProperties() method of CustomTypeDescriptor and return a list of your PropertyDescriptors (created in steps 1-2) for each value you would like to be able to bind to.
  5. Make sure your PropertyDescriptions have their Name property set. This is the property .Net compares your Eval expression to in order to determine which PropertyDescription to use when binding.
  6. Set your CustomTypeDescriptor object (created in steps 3-5) as the DataSource of a WebControl and use Eval() to bind to it dynamically
浅忆流年 2025-01-12 08:17:31

可绑定数据源应实现 IEnumerableIListSource

关于动态方面:请记住,数据绑定的部分魔力是通过反射实现的。

A bindable DataSource should implement either IEnumerable or IListSource.

Regarding the dynamic aspect: keep in mind that part of the magic of databinding happens using reflection.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文