4

I am trying to place a repeater within a repeater using xml data. I have it working exactly as I want, but the method I have used reloads the data for each repeater. I think I need to cast as an XmlNode but I'll be honest - I have no idea where to start.

Here is my code - I'd like to keep everything in the code behind if possible.

<script runat="server">

Public doc As New XmlDocument()

Public Sub Page_Load(ByVal Sender As Object, ByVal E As EventArgs)

    If Not Page.IsPostBack then

        doc.Load(Server.MapPath("~/myxml/bookstore.xml"))

        Dim nodes As XmlNodeList = doc.SelectNodes("Bookings/Booking[@CLIENT_NO='SA33762']")
        rpMyRepeater.DataSource = nodes
        rpMyRepeater.DataBind()

    End If

End Sub

   Protected Sub itemDB(ByVal s As Object, ByVal e As RepeaterItemEventArgs)
      If e.Item.ItemType = ListItemType.Item OrElse e.Item.ItemType = ListItemType.AlternatingItem Then

         Dim rpt As Repeater = CType(e.Item.FindControl("books"), Repeater)

         If Not (rpt Is Nothing) Then

            doc.Load(Server.MapPath("~/myxml/bookstore.xml"))

            Dim nodes2 As XmlNodeList = doc.SelectNodes("Bookings/Booking[@CLIENT_NO='SA33762']/Products/Book")

            rpt.DataSource = nodes2
            rpt.DataBind()

         End If

      End If
   End Sub

</script>

Any ideas?

Tom
  • 12,776
  • 48
  • 145
  • 240

2 Answers2

1

Am I missing something here?

Can't you simply comment/remove your doc.Load(Server.MapPath("~/myxml/bookstore.xml")) out within your itemDB Sub? Since you defined doc "globally" and already loaded it on page load? (by doing that you will already avoid reloading the xml)

That said, I do agree with Caspar that you should rather use the XmlDatasource (especially for its caching abilities), you don't have to use the XmlDatasource within your markup - you can always define it within your code-behind as well - Since you're concerned about people seeing your (asp.net server-side based) markup for some reason...

e.g.

Public Sub Page_Load(ByVal Sender As Object, ByVal E As EventArgs) Handles Me.Load

    If Not Page.IsPostBack Then
        Dim source As New XmlDataSource()
        source.DataFile = "~/myxml/bookstore.xml"
        source.XPath = "Bookings/Booking[@CLIENT_NO='SA33762']"
        rpMyRepeater.DataSource = source
        rpMyRepeater.DataBind()
    End If

End Sub

Markup: (Nice thing you'll notice here, is that we bind the second repeater using the source from the first repeater)

<asp:Repeater ID="rpMyRepeater" runat="server">
    <ItemTemplate>
        <%#XPath("//Booking/NAME/text()")%>
        <asp:Repeater runat="server" ID='books' DataSource='<%#XPathSelect("//Booking/Products/Book") %>'>
            <HeaderTemplate>
                <h2>
                    Books</h2>
            </HeaderTemplate>
            <ItemTemplate>
                <p>
                    Title:
                    <%#XPath("TITLE/text()")%></p>
                <p>
                    <%#XPath("BOOKCODE/text()")%></p>
            </ItemTemplate>
        </asp:Repeater>
    </ItemTemplate>
</asp:Repeater>

XML

<?xml version="1.0" encoding="utf-8" ?>
<Bookings>
  <Booking CLIENT_NO="SA33762">
    <NAME>Mr Pf_Test_15033</NAME>
    <Products>
      <Book>
        <TITLE>My Book</TITLE>
        <BOOKCODE>12345</BOOKCODE>
      </Book>
      <Book>
        <TITLE>My Book2</TITLE>
        <BOOKCODE>123456</BOOKCODE>
      </Book>
    </Products>
  </Booking>
</Bookings>

The implementation using the ListView control (one of my favorite asp.net control) will look something like this: (If there's no books available, it will display the markup within the EmptyDataTemplate)

<asp:Repeater ID="rpMyRepeater" runat="server">
    <ItemTemplate>
        <%#XPath("//Booking/NAME/text()")%>
        <asp:ListView runat="server" ID="books" ItemPlaceholderID="phItems" DataSource='<%#XPathSelect("//Booking/Products/Book") %>'>
            <LayoutTemplate>
                <h2>
                    Books</h2>
                <asp:PlaceHolder runat="server" ID="phItems"></asp:PlaceHolder>
            </LayoutTemplate>
            <ItemTemplate>
                <p>
                    Title:
                    <%#XPath("TITLE/text()")%></p>
                <p>
                    <%#XPath("BOOKCODE/text()")%></p>
            </ItemTemplate>
            <EmptyDataTemplate>
                <p>
                    Sorry no books available</p>
            </EmptyDataTemplate>
        </asp:ListView>
    </ItemTemplate>
</asp:Repeater>
cstruter
  • 1,087
  • 10
  • 20
  • That's just about perfect I think... however, by not including an "onItemDataBond" I don't think I have a way of not showing a customer if they don't have any products (which although it sounds odd, is possible) – Tom Jan 31 '11 at 13:52
  • 1
    Well, you can always substitute the repeater for the listview control instead, since the listview's got like an EmptyDataTemplate which will automatically display if you dont have any data for that user, will add an example quickly – cstruter Jan 31 '11 at 14:13
0

Use an XmlDatasource instead of custom code, better tested, tweaked, optimized, and meets your requirements. Why write something that is already in the framework? ;)

 <asp:xmldatasource
    CacheDuration="Infinite"
    id="XmlDataSource1"
    runat="server"
    XPath="Bookings/Booking[@CLIENT_NO='SA33762']" //<-- test this
    datafile="~/myxml/bookstore.xml" />
Caspar Kleijne
  • 21,552
  • 13
  • 72
  • 102
  • Sounds great... Though I'm kind of asking the question here because I'm a complete novice so it might not be as easy as that! thanks for the tip though. – Tom Jan 26 '11 at 09:53
  • 1
    Since you're a complete novice, I encourage you to KISS your code (keep it short and simple) Don't start reinventing wheels ; – Caspar Kleijne Jan 26 '11 at 09:56
  • I see what you mean but one thing I do know is that my not using code behind code, you'll end up with something that isn't compiled - not the best practice and I'd rather learn to do it the best way than the easiest. – Tom Jan 26 '11 at 10:53
  • there's something to be said for a novice trying to reinvent the wheel. Learn by trying, not succeeding very well, and finally finding a more appropriate bit of prebuilt kit :-) – James Walford Jan 29 '11 at 14:37