6

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?

3
  • Can you share you data model class and the eval expression, that would make it easier to help. Commented Feb 14, 2012 at 22:10
  • "This makes it a nightmare to try and test anything." For example? Commented Feb 14, 2012 at 22:13
  • @Aristos Yes, For this project I am working on an enterprise system that has been developed over 10 years. There are maybe 75 pages or more where we are binding directly to multiple columns on DataRow or DataTable. Commented Feb 14, 2012 at 23:02

2 Answers 2

1

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
Sign up to request clarification or add additional context in comments.

Comments

0

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.

1 Comment

Thanks for the answer. Yes, I've read in MSDN documentation that it uses reflection to do late-binding. However, DataRow is still able to get away with dynamic databinding somehow, so I feel like I should be able to as well.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.