Nesting SPDataSource Controls
Sometimes, when you are using a SPDataSource control to bind to some list control, you might need, inside of it, to fetch information from the item you are iterating over.
Imagine, for example, that you are displaying a list of sites. As usual with SharePoint, there are lots of options for doing this, but consider the SPDataSource approach, which doesn’t require any coding:
1: <SharePoint:SPDataSource runat="server" DataSourceMode="Webs" ID="subsites">
2: <SelectParameters>
3: <asp:Parameter Name="WebID" DefaultValue="RootWeb"/>
4: </SelectParameters>
5: </SharePoint:SPDataSource>
6:
7: <asp:Repeater runat="server" ID="list" DataSourceID="subsites">
8: <ItemTemplate>
9: <!-- show an hyperlink to the subsite and its title -->
10: <asp:HyperLink runat="server" ID="titleLink" Text='<%# Eval("__spTitle") %>' NavigateUrl='<%# Eval("__spDefaultUrl") %>'/>
11: </ItemTemplate>
12: </asp:Repeater>
This is using DataSourceMode=Webs, which, together with parameter RootWeb, displays all subsites under the root site. I’m using a Repeater to display data, but you can use whatever you want.
But now you want to display all lists of each subsite… What would you do then?
OK, we need to get, for each site listed, its id, and store it in some server-side control, such as HiddenField. Next, we add a nested SPDataSource, this time with DataSourceMode=ListOfLists, and add a WebID parameter:
1: <ItemTemplate>
2: <asp:HiddenField runat="server" ID="webid" Value='<%# Eval("__spID") %>'/>
3: <SharePoint:SPDataSource runat="server" DataSourceMode="ListOfLists" ID="lists">
4: <SelectParameters>
5: <asp:ControlParameter Name="WebID" ControlID="webid"/>
6: </SelectParameters>
7: </SharePoint:SPDataSource>
8: ...
9: </ItemTemplate>
Now, all you need is to bind some control, like a Repeater, to the nested SPDataSource. Here is the final code:
1: <asp:Repeater runat="server" ID="list" DataSourceID="subsites">
2: <ItemTemplate>
3: <asp:HiddenField runat="server" ID="webid" Value='<%# Eval("__spID") %>'/>
4: <SharePoint:SPDataSource runat="server" DataSourceMode="ListOfLists" ID="lists">
5: <SelectParameters>
6: <asp:ControlParameter Name="WebID" ControlID="webid"/>
7: </SelectParameters>
8: </SharePoint:SPDataSource>
9:
10: <asp:Repeater runat="server" DataSourceID="lists">
11: <ItemTemplate>
12: <p><asp:Literal runat="server" ID="l" Text='<%# Eval("__spTitle") %>'/></p>
13: </ItemTemplate>
14: </asp:Repeater>
15: <div class="area-item">
16: <asp:HyperLink runat="server" ID="titleLink" Text='<%# Eval("__spTitle") %>' NavigateUrl='<%# Eval("__spDefaultUrl") %>'/>
17: </div>
18: </ItemTemplate>
19: </asp:Repeater>
If you are curious, the MSDN page SPDataSource.SelectParameters lists all predefined parameters that the SPDataSource will recognize automatically, and this page in Solutionizing .NET lists all fields returned by SPDataSource, in all of its modes. BTW, a great resource!
If you want to improve things a bit, you might want to set the filter query on the nested SPDataSource’s SelectCommand property. I leave that as an exercise to you, dear reader!