Friday, February 4, 2011

Programmatically accessing Data in an ASP.net 2.0 Repeater

This is an ASP.Net 2.0 web app. The Item template looks like this, for reference:

<ItemTemplate>
 <tr>
  <td class="class1" align=center><a href='url'><img src="img.gif"></a></td>
  <td class="class1"><%# DataBinder.Eval(Container.DataItem,"field1") %></td>
  <td class="class1"><%# DataBinder.Eval(Container.DataItem,"field2") %></td>
  <td class="class1"><%# DataBinder.Eval(Container.DataItem,"field3") %></td>
  <td class="class1"><%# DataBinder.Eval(Container.DataItem,"field4") %></td>
 </tr>
</ItemTemplate>

Using this code in the bowels of the codebehind:

foreach (RepeaterItem item in rptrFollowupSummary.Items)
{
 string val = ((DataBoundLiteralControl)item.Controls[0]).Text;
 Trace.Write(val);
}

I produce this:

<tr>
<td class="class1" align=center><a href='url'><img src="img.gif"></a></td>
<td class="class1">23</td>
<td class="class1">1/1/2000</td>
<td class="class1">-2</td>
<td class="class1">11</td>
</tr>

What I need is the data from Field1 and Field4

I can't seem to get at the data the way I would in say a DataList or a GridView, and I can't seem to come up with anything else on Google or quickly leverage this one to do what I want. The only way I can see to get at the data is going to be using a regex to go and get it (Because a man takes what he wants. He takes it all. And I'm a man, aren't I? Aren't I?).

Am I on the right track (not looking for the specific regex to do this; forging that might be a followup question ;) ), or am I missing something?

  • Since you are working with tabular data, I'd recommend using the GridView control. Then you'll be able to access individual cells.

    Otherwise, you can set the td's for Field1 and Field4 to runat="server" and give them ID's. Then in the codebehind, access the InnerText property for each td.

    From ern
  • If you can afford a smidge more overhead in the generation, go for DataList and use the DataKeys property, which will save the data fields you need.

    You could also use labels in each of your table cells and be able to reference items with e.Item.FindControl("LabelID").

    From Dillie-O
  • Off the top of my head, you can try something like this:

    <ItemTemplate>
            <tr>
                <td "class1"><asp:Literal ID="litField1" runat="server" Text='<%# Bind("Field1") %>'/></td>
                <td "class1"><asp:Literal ID="litField2" runat="server" Text='<%# Bind("Field2") %>'/></td>
                <td "class1"><asp:Literal ID="litField3" runat="server" Text='<%# Bind("Field3") %>'/></td>
                <td "class1"><asp:Literal ID="litField4" runat="server" Text='<%# Bind("Field4") %>'/></td>
            </tr>
    </ItemTemplate>
    

    Then, in your code behind, you can access each Literal control as follows:

    foreach (RepeaterItem item in rptrFollowupSummary.Items)
    {   
        Literal lit1 = (Literal)item.FindControl("litField1");
        string value1 = lit1.Text;
        Literal lit4 = (Literal)item.FindControl("litField4");
        string value4 = lit4.Text;
    }
    

    This will add to your ViewState but it makes it easy to find your controls.

    From Alison
  • The <%#DataBinder.Eval(...) %> mechanism is not Data Binding in a "strict" sense. It is a one-way technique to put text in specific places in the template.

    If you need to get the data back out, you have to either:

    1. Get it from your source data
    2. Populate the repeater with a different mechanism

    Note that the Repeater doesn't save the DataSource between postbacks, You can't just ask it to give you the data later.

    The first method is usually easier to work with. Don't assume that it's too expensive to reacquire your data from the source, unless you prove it to yourself by measuring; it's usually pretty fast. The biggest problem with this technique is if the source data can change between calls.

    For the second method, a common technique is to use a Literal control. See Alison Zhou's post for an example of how to do it. I usually personally prefer to fill the Literal controls inside of the OnItemDataBound instead

  • The Repeater in this case is set in stone so I can't switch to something more elegant. Once upon a time I did something similar to what Alison Zhou suggested using DataLists, but it's been some time (2+ years) and I just completely forgot about doing it this way. Yeesh, talk about overlooking something obvious. . .

    So I did as Alison suggested and it works fine. I don't think the viewstate is an issue here, even though this repeater can get dozens of rows. I can't really speak to the question if doing it that way versus using the instead (but that seems like a fine solution to me otherwise). Obviously the latter is less of a viewstate footprint, but I'm not experienced enough to say when one approach might be preferrable to another without an extreme example in front of me. Alison, one question: why literals and not labels?

    Euro Micelli, I was trying to avoid a return trip to the database. Since I'm still a little green relative to the rest of the development world, I admit I don't necessarily have a good grasp of how many database trips is "just right". There wouldn't be a performance issue here (I know the app's load enough to know this), but I suppose I was trying to avoid it out of habit, since my boss tends to emphasize fewer trips where possible.

    From peacedog
  • @peacedog:

    Correct; Alison's method is perfectly acceptable.

    The trick with the database roundtrips: they are not free, obviously, but web servers tend to be very "close" (fast, low-latency connection) to the database, while your users are probably "far" (slow, high-latency connection).

    Because of that, sending data to/from the browser via cookies, ViewState, hidden fields or any other method can actually be "worse" than reading it again from your database. There are also security implications to keep in mind (Can an "evil" user fake the data coming back from the browser? Would it matter if they do?).

    But quite often it doesn't make any difference in performance. That's why you should do what works more naturally for your particular problem and worry about it only if performance starts to be a real-world issue.

    Good luck!

0 comments:

Post a Comment