title: ASP.NET VB Nested Listviews
body: <p>I have an outer listview and inside its itemtemplate an inner listview. Each has its own SQLDataSource. A Id field from the outerlistview works as a select parameter for the second listview.</p>
  
  <p>When stepping through with the debugger it works perfectly, unfortunately the rendered page only contains data from the outer listview. It appears the databinding of the outer listview fires and renders the page (including the inner listview) before the codebehind can provide a where parameter to the second listview.</p>
  
  <p>The aspx page is below.</p>
  
  <pre><code>&lt;%@ Page Title="Nested ListView" Language="VB" MasterPageFile="~/MasterPages/SimpleMasterPage.master"
      CodeFile="NLV2PA_A.aspx.vb" Inherits="Demos_NLV2PA_A" %&gt;
  
  
  &lt;asp:Content ID="Content1" ContentPlaceHolderID="head" runat="Server"&gt;
  &lt;/asp:Content&gt;
  
  &lt;asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server"&gt;
  
      &lt;asp:ListView ID="ListView1" runat="server" ItemPlaceholderID="PlaceHolder1" DataKeyNames="Id"
          DataSourceID="SqlDataSource1"&gt;
  
          &lt;LayoutTemplate&gt;
              &lt;asp:PlaceHolder runat="server" ID="PlaceHolder1"&gt;&lt;/asp:PlaceHolder&gt;
          &lt;/LayoutTemplate&gt;
          &lt;EmptyDataTemplate&gt;
              &lt;span&gt;ListView 1 No data was returned. &lt;/span&gt;
          &lt;/EmptyDataTemplate&gt;
          &lt;ItemTemplate&gt;
              &lt;span style=""&gt;Id:
                  &lt;asp:Label ID="IdLabel" runat="server" Text='&lt;%# Eval("Id") %&gt;' /&gt;
                  &lt;br /&gt;
                  Name:
                  &lt;asp:Label ID="NameLabel" runat="server" Text='&lt;%# Eval("Name") %&gt;' /&gt;
                  &lt;br /&gt;
                  &lt;br /&gt;
              &lt;/span&gt;
              &lt;asp:ListView ID="ListView2" runat="server" ItemPlaceholderID="PlaceHolder2" DataSourceID="SqlDataSource2"&gt;
                  &lt;LayoutTemplate&gt;
                      &lt;asp:PlaceHolder runat="server" ID="PlaceHolder2"&gt;&lt;/asp:PlaceHolder&gt;
                  &lt;/LayoutTemplate&gt;
                  &lt;EmptyDataTemplate&gt;
                      &lt;span&gt;ListView2 No data was returned. &lt;/span&gt;
                  &lt;/EmptyDataTemplate&gt;
                  &lt;ItemTemplate&gt;
                      &lt;span style=""&gt;Title:
                          &lt;asp:Label ID="TitleLabel" runat="server" Text='&lt;%# Eval("Title") %&gt;' /&gt;
                          &lt;br /&gt;
                          &lt;h1&gt;
                              &lt;%# Eval("Title") %&gt;&lt;/h1&gt;
                          &lt;br /&gt;
                          Summary:
                          &lt;asp:Label ID="SummaryLabel" runat="server" Text='&lt;%# Eval("Summary") %&gt;' /&gt;
                          &lt;br /&gt;
                          PhotoAlbumID:
                          &lt;asp:Label ID="PhotoAlbumIdLabel" runat="server" Text='&lt;%# Eval("PhotoAlbumId") %&gt;' /&gt;
                          &lt;br /&gt;
                          &lt;br /&gt;
                      &lt;/span&gt;
                  &lt;/ItemTemplate&gt;
              &lt;/asp:ListView&gt;
          &lt;/ItemTemplate&gt;
      &lt;/asp:ListView&gt;
      &lt;asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="&lt;%$ ConnectionStrings:RenaissanceConnectionString1 %&gt;"
          SelectCommand="SELECT [Id], [Name] FROM [PhotoAlbum] ORDER BY [Id]"&gt;&lt;/asp:SqlDataSource&gt;
      &lt;asp:SqlDataSource ID="SqlDataSource2" runat="server" ConnectionString="&lt;%$ ConnectionStrings:RenaissanceConnectionString1 %&gt;"
          SelectCommand="SELECT [Title], [Summary], [PhotoAlbumId] FROM [Apartments] WHERE ([PhotoAlbumId] = @PAId)"&gt;
          &lt;SelectParameters&gt;
              &lt;asp:ControlParameter ControlID="ListView1" DefaultValue="0" Name="PAId" PropertyName="SelectedValue"
                  Type="Int32" /&gt;
          &lt;/SelectParameters&gt;
      &lt;/asp:SqlDataSource&gt;
  &lt;/asp:Content&gt;
  </code></pre>
  
  <p>The code behind is</p>
  
  <pre><code>Protected Sub ListView1_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.ListViewItemEventArgs) Handles ListView1.ItemDataBound
  
      If e.Item.ItemType = ListViewItemType.DataItem Then
          SqlDataSource2.SelectParameters("PAId").DefaultValue = DirectCast(e.Item.FindControl("IdLabel"), Label).Text
      End If
  End Sub
  </code></pre>
  
  <p>The output to the browser is:</p>
  
  <pre><code>Id: 8 
  Name: First set of Photos 
  
  ListView2 No data was returned.
  
  Id: 9 
  Name: Second set of Photos 
  
  ListView2 No data was returned.
  
  etc.
  </code></pre>
  
  <hr>
  
  <p>Microsoft make the point in an old article that:</p>
  
  <blockquote>
    <p>You could, in theory, intercept the
    ItemDataBound event of the parent
    ListView, walk your way through the
    control tree, grab a reference to the
    child ListView, and bind it
    programmatically to data. If you do,
    you won't throw an exception, but the
    binding command on the inner ListView
    is lost because it fires too late to
    affect the rendering.</p>
  </blockquote>
  
  <p>Unfortunately, they don't tell me how to fix it.</p>
  
  <p>If there is any genius out there who could tell me how to get this to work it would be much appreciated.</p>