views:

308

answers:

4

I have this following data source binding:

MembershipProvider provider = new MembershipProvider();
UserUpdateLogs userUpdateLogs = provider.GetUserUpdateLogs(username);

dgUserUpdateLog.DataSource = userUpdateLogs.Logs;
dgUserUpdateLog.DataBind();

Logs is a collection of UserUpdateLogEntry. This class owns the UserData Property, and UserData contains other properties. My aspx:

<Columns>
<asp:BoundColumn DataField="ChangeDate" Visible="true" HeaderText="Date"/>
<asp:BoundColumn DataField="UserData.Sex" HeaderText="Sex" />
<asp:BoundColumn DataField="UserData.Phone" HeaderText="Phone" />
</Columns>

The first row (ChangeDate) seems to work well. But when rendering the second BoundColumn, the following error is shown:

A field or property with the name 'UserData.Sex' was not found on the selected data source.

Why does it happen? Can't Aspx recognize a concatenation of properties like PropertyA.PropertyB?

I've checked the object and all properties have valid data.

+1  A: 

C# is using reflection to look for a property called UserData.Sex, it is not smart enough to search for UserData and then Sex.
So the answer to your question is 'No'.

There are several ways to get around this, but the more elegant ways are either to add a property UserSex, or to flatten the object into a data table. At the moment, I can't think of a good way that doesn't break OO.

Kobi
+3  A: 

You can not bind to properties of sub-objects in that way.

As an alternative, you can use a template column and use Eval to display the properties of the sub-object, e.g. something like this:

<asp:TemplateColumn HeaderText="Sex" Visible="true">
  <ItemTemplate>
    <asp:Literal runat="server" Text='<%# Eval("UserData.Sex") %>' /> 
  </ItemTemplate>
</asp:TemplateColumn>
<asp:TemplateColumn HeaderText="Phone" Visible="true">
  <ItemTemplate>
    <asp:Literal runat="server" Text='<%# Eval("UserData.Phone") %>' /> 
  </ItemTemplate>
</asp:TemplateColumn>
M4N
+1  A: 

I'm not sure what to tell you about why it won't work, but a workaround to write this might be to use some linq2objects:

dgUserUpdateLog.DataSource = (from n in userUpdateLogs.Logs select new {n.ChangeDate, Sex=n.Userdata.Sex, Phone=n.UserData.Phone});

then:

<Columns>
<asp:BoundColumn DataField="ChangeDate" Visible="true" HeaderText="Date"/>
<asp:BoundColumn DataField="Sex" HeaderText="Sex" />
<asp:BoundColumn DataField="Phone" HeaderText="Phone" />
</Columns>
John Boker
I am using .net 2.0, otherwise it could be a good workaround, thanks!
Victor Rodrigues
+2  A: 

One thing that you can do is create an accessor property:

public string UserSex
{
    get { return userUpdateLogs.Logs.UserData.Sex; }
}
Gavin Miller