score:2

Accepted answer

The is iterating over a collection that contains MilhouseHour objects: the IGrouping. MilhouseHour does indeed contain a reference to aspnet_User, but the thing that you want to refer to, the name (and the id) is a property of the aspnet_User, not the MilhouseHour. Ideally, you'd be able to write markup like

  <asp:CheckBoxList ID="shiftsSun" runat="server" 
    DataSource='<%#Eval("hourUsers")%>' 
    DataTextField = "aspnet_User.UserName"
    DataValueField = "aspnet_User.UserId" />

But that gives an error. ASP.Net is expecting in the DataTextField the name of a property that it will invoke (presumably by reflection) on the object in question, not an expression to evaluate. The object in question is a MilhouseHour, which doesn't have a property called "aspnet_User.UserName".

You have a number of options.

  1. Do what you did originally, and group x.aspnet_User instead of x in your LINQ expression. Then the thing iterated over by the CheckBoxList will be an IGrouping, which will have properties "UserName" and "UserId" that will work.
  2. Avoid using CheckBoxList and use something that will let you control the code in the inner loop a bit more explicitly, such as repeater:

    <asp:TemplateField HeaderText="Sunday">
    <ItemTemplate>
        <asp:Repeater ID="shiftsSun" runat="server" DataSource='<%#Eval("hourUsers")%>'>
            <ItemTemplate>
                <asp:CheckBox runat="server" 
                   Text='<%# Eval("aspnet_User.UserName")  %>' 
                   Value='<%# Eval("aspnet_User.UserId") %>' />
                <br />
            </ItemTemplate>
        </asp:Repeater>
    </ItemTemplate>
    

There are probably many more options, but that's what occurs to me at the moment.

score:1

I don't think you're missing any major concepts. The group query produces a collection of IGrouping, where Whatever is the type of the objects in the MilhouseHours collection. (I can't get a bigger picture for your object model.) You then bind those groupings to a CheckBoxList's data source. You're missing a DataTextField="NameField" directive, but no major concepts. Here's some code that works, that's at least related to your problem, if not identical:

        <asp:GridView ID="myGrid" runat="server" AutoGenerateColumns="false">
        <Columns>
            <asp:TemplateField>
                <ItemTemplate>
                    <%# Eval("hourUsers.Key") %>
                </ItemTemplate>
            </asp:TemplateField>

            <asp:TemplateField HeaderText="Sunday">
                <ItemTemplate>
                    <asp:CheckBoxList ID="shiftsSun" runat="server" 
                        DataSource='<%#Eval("hourUsers")%>' 
                        DataTextField = "Name"
                        DataValueField = "Id" />
                </ItemTemplate>
            </asp:TemplateField>
        </Columns>
    </asp:GridView>

And in the pagebehind:

    class UserHour
    {
        public string Name {get;set;}
        public int Id { get; set; }
        public string Hour { get; set; }
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        var users = new List<UserHour>
                        {
                                    new UserHour {Name = "Fred", Id = 1, Hour = "0800"},
                                    new UserHour {Name = "Fred", Id = 1, Hour = "0900"},
                                    new UserHour {Name = "Fred", Id = 1, Hour = "1000"},
                                    new UserHour {Name = "Bob", Id = 2, Hour = "0900"},
                                    new UserHour {Name = "Bob", Id = 2, Hour = "1000"},
                        };
        var result = from x in users
                     group x by x.Hour
                     into hour select new
                                          {
                                                      hourStr = hour.Key, hourUsers = hour
                                          };

        myGrid.DataSource = result;
        myGrid.DataBind();
    }

Related Articles