Declarative data binding on User Controls

I had this problem a few years ago and figured that there was no good solution, but I am older and wiser now so figured it’s time look for a better solution.

I have a GridView, and inside the ItemTemplate I call one of my own UserControls:


<asp:GridView ID="grdMessages" runat="server" ... >
  ...
  <ItemTemplate>
    <uc1:EmailAddress ID="EmailAddress1" runat="server" 

      DataSource='<%# (MailAddress)Eval("FromAddress") %>' />
  </ItemTemplate>
  ...
</asp:GridView>

But the DataSource property of the EmailAddress user control is never set. If I have a plain <%# Eval("FromAddress") %> right next to the <uc1:EmailAddress /> tag, the literal evaluates properly. The user control doesn’t.

My original solution was to just set the value of the user control’s properties in the code behind class. But I shouldn’t have to do that. (It’s also a bit annoying to do that because I’d have to handle the GridView’s DataBinding event and then find the control and update it.)

There’s got to be a better way!

I overrode the user control’s DataBind and DataBindChildren methods, to see if they were being called. They were.

So then I tried it with a Literal control, setting the Text property. Probably the simplest .NET Web Control there is. Obviously that worked, because that’s how data binding is supposed to work. So there must be something that the Literal control does that mine doesn’t. Time to pull out Reflector!

The Literal.Text property has an attribute called Bindable. Could this be it? It makes sense. Its full name is System.ComponentModel.Bindable. Does it work? Nope.

Hang on a tick… the DataSource property is being set now. So what is my problem? The code that’s doing the work is in the Load event handler. But the DataSource property is being set after Load. So I’ve moved that code to PreRender and…

It works!

So what have we learnt?

To make a UserControl’s property bindable, you must use the [Bindable] attribute. And those properties will not get bound until after Load, so don’t put code that relies on your bound properties in the Load event handler!

ObjectDataSource.SelectCountMethod wants an int

I have been working with the GridView ASP.NET control today, bound to an ObjectDataSource. This is to do with my experiment with DBMail that I mentioned the other day. It wasn’t working. I couldn’t find a solution on the net. By chance, I changed this:

    class DatabaseSource
    {
        long _messageCount = 0;

        public List<Message> GetMessages(long startRow, int pageSize)
        {
            Database db = new Database();
            List<Message> messages = db.GetMessages( startRow, pageSize,


               out _messageCount);

            return messages;
        }

        public long GetMessageCount()
        {
            return _messageCount;
        }
    }

into this:

    class DatabaseSource
    {
        long _messageCount = 0;

        public List<Message> GetMessages(long startRow, int pageSize)
        {
            Database db = new Database();
            List<Message> messages = db.GetMessages( startRow, pageSize,


               out _messageCount);

            return messages;
        }

        public int GetMessageCount()
        {
            return Convert.ToInt32(_messageCount);
        }
    }

Notice the difference?

To get the ObjectDataSource to work, the SelectCountMethod has to return an 32-bit integer (System.Int32). It failed (without an error message) when it was provided with a long or 64-bit integer (System.Int64).

It turns out it’s written in the documentation in black and white:

Type: System.String

A string that represents the name of the method or function that the ObjectDataSource uses to retrieve a row count. The method must return an integer (Int32). The default is an empty string ("").

Who would have thought?

Hopefully this will save someone who is running into the same problem. (That’s assuming that this will pop up in their search results when they search for ObjectDataSource and GridView paging not working!)