views:

343

answers:

3

I'm using a linq group by query (with two grouping parameters) and would like to use the resulting data in a nested repeater.

var dateGroups = from row in data.AsEnumerable()
    group row by new { StartDate = row["StartDate"], EndDate = row["EndDate"] };

"data" is a DataTable from an SqlDataAdapter-filled DataSet. "dateGroups" is used in the parent repeater, and I can access the group keys using Eval("key.StartDate") and Eval("key.EndDate").

Since dateGroups actually contains all the data rows grouped neatly by Start/End date, I'd like to access those rows to display the data in a child repeater.

To what would I set the child repeater's DataSource? I have tried every expression in markup I could think of; I think the problem is that I'm trying to access an anonymous member (and I don't know how.) In case it doesn't turn out to be obvious, what would be the expression to access the elements in each iteration of the child repeater?

Is there an expression that would let me set the DataSource in the markup, or will it have to be in the codebehind on some event in the parent repeater?

A: 

I think the problem is that I'm trying to access an anonymous member (and I don't know how.)

Can you replace the anonymous type with your own class?

David B
+1  A: 

Use a know class type rather than an anonymous class. Otherwise you will have to use reflection to inspect the anonymous type which gets ugly.

Raj Kaimal
After figuring out how to access the anonymous member with the ToDictionary expression, I realized I still didn't have the kind of access to the other members that I needed for the inner gridview.I created a two-member class for the key, then on each repeater iteration filtered the original DataTable for the inner gridview.
Duke
+2  A: 

I ended up searching around a little more and found this. Using that I created a Dictionary whose key is the StartDate/EndDate combination, and value is a list of DataRows:

var dateGroups = (from row in data.AsEnumerable()
    group row by new
    {
        StartDate = row["StartDate"],
        EndDate = row["EndDate"]
    } into g select g)
    .ToDictionary(gdc => gdc.Key, gdc => gdc.ToList());

The parent Repeater is programmatically bound, and now I have an inner GridView bound to the list of DataRows:

<asp:Repeater ID="CourseScheduleRepeater" runat="server">
    <ItemTemplate>
        <h4><%# Eval("key.StartDate", "{0:MMM. dd, yyyy}") %> - <%# Eval("key.EndDate", "{0:MMM. dd, yyyy}") %></h4>

        <asp:GridView ID="GridView1" runat="server"
                DataSource='<%# Eval("value") %>'>
            <Columns>
                <asp:TemplateField HeaderText="Section">
                    <ItemTemplate>
                        <%# DataBinder.Eval(Container.DataItem, "[SectionCode]") %>
                    </ItemTemplate>
                </asp:TemplateField>
                <asp:TemplateField HeaderText="Location">
                    <ItemTemplate>
                        <%# DataBinder.Eval(Container.DataItem, "[LocationName]") %>
                    </ItemTemplate>
                </asp:TemplateField>
                <asp:TemplateField HeaderText="Schedule">
                    <ItemTemplate>
                        <%# DataBinder.Eval(Container.DataItem, "[Schedule]") %>
                    </ItemTemplate>
                </asp:TemplateField>
            </Columns>        
        </asp:GridView>

    </ItemTemplate>
</asp:Repeater>

My only complaint is that I have to use template fields and that there are two extra columns showing up in the GridView - "RowError" and "HasErrors". Anyone know why those columns would be coming up?

Duke