views:

208

answers:

6

My datasource has an Rating dataItem contains an integer from 0 to 5. I'd like to print stars accordignly.

I'm trying to do it within Repeater control:

<b>Rating:</b>

<% for (int j = 1; j <= DataBinder.Eval(Container.DataItem, "Rating"); j++)
{  %>
<img src="App_Pics/fullstar.png" />
<% }
for (int j = 1; j <= 5 - DataBinder.Eval(Container.DataItem, "Rating"); j++)
{ %>
<img src="App_Pics/emptystar.png" />
<%} %>
  1. I get the error The name 'Container' does not exist in the current context. It is weird, because when I used <%# DataBinder.Eval(Container.DataItem, "Name")%> a line before, it worked great.
  2. Is it clever to include loops in my aspx page? I think it's not very convenient. What's my alternatives?
  3. What's that # means?

Thank you very much.

+2  A: 

The # indicates a databound item, which is why you're seeing the error you've mentioned; you're using DataBinding outside of it's context.

The best solution would be to convert your star rater into an external control (an ascx control). You can add a property called "Rating", assign it from your databound context, and do the looping within the star rater control.

jvenema
+1  A: 

Point 2, you certainly can do it, and you'll find a few examples of it in tutorials and stuff. Personally I like to try and keep as much code as possible in the codebehind, but sometimes it's not worth it...

Martin Milan
A: 

I'm not sure loops are such a great idea with a Repeater control. Better practise is to loop the DataSource itself (in the code-behind), so the Repeater only needs a single iteration to render the HTML.

If you need some composite HTML structure for display, I'd go with jvenema's solution and use another UserControl to render it.

Prutswonder
+3  A: 

The # indicates code to be executed when data-binding occurs (i.e. when DataBind() is called on the control or the page). The <%# %> syntax is the data-binding equivilent of <%= %> so unfortunately you can't just wrap your loop in <%# %> blocks and be done with it.

You can around this limitation by implementing a code-behind method and passing the rating to the method:

<%# GetStars(Convert.ToInt32(DataBinder.Eval(Container.DataItem, "Rating"))) %>

And then implement the method as:

protected string GetStars(int rating)
{
    string output = string.Empty;
    for (int j = 1; j <= rating; j++) output += "<img src=\"App_Pics/fullstar.png\" />";
    for (int j = 1; j <= 5 - rating; j++) output += "<img src=\"App_Pics/emptystar.png\" />";
    return output;
}
Chris Pebble
Actually, I liked your way the best. thank you.BTW, is there any difference between output = "" and output = string.Empty?
iTayb
@iTayb, string.Empty is a preferred method of designating an empty string value, but not everybody agrees. See: http://stackoverflow.com/questions/263191/in-c-should-i-use-string-empty-or-string-empty-or
Anthony Pegram
There's no practical different between "" and string.Empty. The only reason I use it is to demonstrate my intent (i.e. I meant to create an empty string).
Chris Pebble
@Anthony great thread. Thank you.
iTayb
protip: use StringBuilder
ANeves
@sr pt: Using a StringBuilder is actually slower in this case. I just ran the loop above and a variant using StringBuilder a million times and found the StringBuilder to be about 18% slower. Of course each loop takes about 0.0007MS so I've just wasted five minutes of my life in micro-optimization theatre. Argg. Just wanted to make the point that using StringBuilder isn't necessarily a protip. It depends.
Chris Pebble
+1  A: 

I would not recommend using a loop that way. There are, of course, ways to put 5 images together like you need them with stars on or off, but another idea is to simply create 6 static images, with 0 to 5 stars turned on. 0star.jpg, 1star.jpg, etc. Then your "rating" value can be used simply to generate the appropriate filename.

Anthony Pegram
A: 

The best would be for me to have something like :

codebehind :

protected List<int> Stars = new List<int> { 1, 2, 3, 4, 5 };
protected int RankingStars = 3;

aspx :

<asp:Repeater runat=server ID=C_Rep_StarsFull DataSource=Stars >
    <ItemTemplate>
          <img src="App_Pics/fullstar.png" runat=server 
                visible=<%# RankingStars >= (int)Container.DataItem %>/>
    </ItemTemplate>
</asp:Repeater>
<asp:Repeater runat=server ID=C_Rep_StarsEmpty DataSource=Stars >
    <ItemTemplate>
          <img  src="App_Pics/emptystar.png" runat=server 
                visible=<%# RankingStars < (int)Container.DataItem %>/>
    </ItemTemplate>
</asp:Repeater>
Yoann