Label in Repeater - Change text on output

Hi everyone,

I tried this technique as suggested on another forum and a couple of other things, suggested on SitePoint as well as others but to no avail. Im trying to find the Label in the repeater to display information depending on the output. However I was presented with the following error:

[I]"Index was out of range. Must be non-negative and less than the size of the collection.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index"[/I]

It highlights the problematic script as:
Label lblStatus = rptGeneralEnq.Items[0].FindControl(“lblStatus”) as Label;

I’m trying to access the Label, in the repeater, so that depending on if the text origionally displays true or false (as the label grabs the ‘bit’ datatype for that record to display) to then change the text to something more appropriate (completed/outstanding) - if at all possible.

Heres my attempt:

C#:

   1. protected void Page_Load(object sender, EventArgs e)
   2.  {
   3.
   4.        Label lblStatus = rptGeneralEnq.Items[0].FindControl("lblStatus") as Label;
   5.
   6.             if (lblStatus.Text == "True")
   7.             {
   8.                 lblStatus.Text = "<font color='green'>Completed</font>";
   9.             }
  10.             else
  11.             {
  12.                 lblStatus.Text = "<font color='red'>Outstanding</font>";
  13.             }
  14. }  

.ASPX

<asp:Repeater ID="rptGeneralEnq" runat="server" DataSourceID="SqlGeneralEnq" onitemcommand="rptGeneralEnq_ItemCommand">
     <ItemTemplate>
        <div id="generalenquiry">
        <div class="right_col">
            <span class="enqhist_title floatright">Received: <strong><%#((System.DateTime)DataBinder.Eval(Container.DataItem, "Received")).ToShortDateString()%></strong></span>
            <span class="enqhist_title">Status: <strong><asp:Label ID="lblStatus" runat="server" Text="<%#Eval("Responded")%>" /></asp:Label></strong></span>
</div>
</div>
</ItemTemplate>
</asp:Repeater>


I had, before hand, tried the code in the repeater itself, but without rptGen… instead was just

Label lblStatus = (Label)e.Item.FindControl(“lblStatus”); …Then the logic after it. - The result of that was the text displays ‘/>’

Label in the aspx page and repeater reads: Status: <strong><asp:Label ID=“lblStatus” runat=“server” Text=“<%#Eval(“Responded”)%>” /></asp:Label></strong></span>

Any help is appreciated,

Thanks,

Daniel

You would need to do it in a loop or in reapeater databound event:


foreach (RepeaterItem ri in rptGeneralEnq.Items)
{
Label lblStatus = ri.FindControl("lblStatus") as Label;  
if (lblStatus != null)
{
//ETC
}
}


It is the best though to do it on ItemDataBound event. If you post the code you have there, we can try and help a bit further like that

[/QUOTE] …It is the best though to do it on ItemDataBound event. If you post the code you have there, we can try and help a bit further like that[/QUOTE]

Not sure I’m using ItemDataBound, I do have ItemCommand as posted below:

C#:


protected void rptGeneralEnq_ItemCommand(object source, RepeaterCommandEventArgs e)
    {
        HiddenField GenEnqID = (HiddenField)e.Item.FindControl("hdnID");

        AdminUser user = AdminUser.GetCurrentUser();

        if (user == null)
        {
            Response.Redirect("~/Login.aspx");
        }

        if (user.Authority == ("Admin"))
        {
            if (e.CommandName == "Delete")
                GeneralEnqRes.Delete(int.Parse(GenEnqID.Value));

            Response.Redirect("~/Admin/GeneralEnq.aspx");
        }
        else
        {
            Response.Redirect("~/Admin/Unauthorised.aspx");
        }
    }

With that said I’m unsure of how to create a ItemDataBound event, only ever used ItemCommand. Is it just a case of declaring the property in the aspx page, inside the repeater, like I would ItemCommand, then creating the event in the C# Logic file?

Yes, the process is the same, just a different event. Item command only fires when a item is selected. Like a link in the gridview or something. OnItemDataBound, is when the gridview is loaded. So it depends if you want to do this on click or on load

First of all, my apologies for the delayed response, NightStalker.

I’ve been messing around with it, the OnItemDataBound event is now in there and when I call it in page load im presented with

CS1501: No overload for method ‘rptGeneralEnq_ItemDataBound’ takes ‘0’ arguments.

I’m not sure what arugments to call as the script in the ItemDataBound is that which you suggested. So im rather puzzled. :confused: Unless I’m completely on the wrong tracks in thinking that I can just simply call it like a method :S

Page_Load:

protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
AdminUser user = AdminUser.GetCurrentUser();

        if (user == null)
        {
            Response.Redirect("~/Login.aspx");
        }

        if (GeneralEnqRes.GenEnqResponse() &gt; 0)
        {
            rptGeneralEnq.Visible = true;
        }
        else
        {
            rptGeneralEnq.Visible = false;
            lblMessage.Text = "There are no General Enquiries to view.";
        }

        rptGeneralEnq_ItemDataBound();

}
}

rptGeneralEnq_ItemDataBound:


protected void rptGeneralEnq_ItemDataBound(object source, RepeaterItemEventArgs e)
    {
        foreach (RepeaterItem ri in rptGeneralEnq.Items)
        {
            Label lblStatus = ri.FindControl("lblStatus") as Label;
            if (lblStatus != null)
            {
                if (lblStatus.Text == "True")
                {
                    lblStatus.Text = "<font color='green'>Completed</font>";
                }
                else if (lblStatus.Text == "False")
                {
                    lblStatus.Text = "<font color='red'>Outstanding</font>";
                }
            }
        }        
    }

In addition, just a thought, I use a sqldatasource control to retreive the information for the repeater, would this impair the ItemDataBound event? I can alteratively create a LINQ to SQL Method and databind in the page_load event if it does.

Regards,

Daniel

Hi, no problem. Messing around with things is the best way to learn.

The databound bound event is executed for each item as it is bound to the repeater. So your code is looping through every item in the repeater, everytime an item is added. The easiest way to add the method is to go to design mode in Visual Studio, select the repeater, the double click on the ItemDataBound event, and it will create it and wire it up to the repeater for you.

But, you got it in, so im sure you figured that out

Take your code out of the foreach loop and replace the following:

Label lblStatus = ri.FindControl(“lblStatus”) as Label;
with

Label lblStatus = e.Item.FindControl(“lblStatus”) as Label;

As e is reference to the current item that is been databound. If you are using linq objects to bind to the repeater, you could also do something like this:

yourObj o = (yourObj)e.Item.DataItem;

I hope this helps. Let me know if anything is not 100% clear and I will try and explain a little more.

Good luck

That did clear it up - I don’t need to call it (As its already being called by repeater - per item (automatically looping, being a repeater)) - Hope thats right :slight_smile:

So I changed the <asp:Label> slightly - instead of putting:


<asp:Label ID="lblStatus" runat="server" Text="<%#Eval("Responded")%>" ></asp:Label>

Which, once i ran the page, caused the Text to appear, />

I now have moved the text out of the label’s properties specifics and inbetween the start and end tags of the label:

Status: <strong><asp:Label ID=“lblStatus” runat=“server”><%#Eval(“Responded”)%>"</asp:Label>

The page runs and displays, but just the standard ‘true’ or ‘false’.


protected void rptGeneralEnq_ItemDataBound(object source, RepeaterItemEventArgs e)
    {
        Label lblStatus = e.Item.FindControl("lblStatus") as Label;
        if (lblStatus != null)
        {
            if (lblStatus.Text == "True")
            {
                lblStatus.Text = "<font color='green'>Completed</font>";
            }
            else if (lblStatus.Text == "False")
            {
                lblStatus.Text = "<font color='red'>Outstanding</font>";
            }
        }
    } 

I’m thinking that with it inbetween the label tags the script is not taking effect? and with it in i must be called the Eval wrong?

Any extra info needed i’ll do my best to provide

Regards,

Daniel

P.S. I’m calling the ItemDataBound - <asp:repeater id=“rptGeneralEnq” runat=“server” OnItemDataBound=“rptGeneralEnq_ItemDataBound” etc… - Hope thats right also

What type of object are you binding to the repeater? A class with a “Responded” property?

If so, it would be better to do it like this:

<asp:Label ID=“lblStatus” runat=“server”></asp:Label>


Label lblStatus = e.Item.FindControl("lblStatus") as Label;
yourClass c = e.Item.DataItem as yourClass;

if (yourClass != null)
{
if (youClass.Responded)
            {
                lblStatus.Text = "<font color='green'>Completed</font>";
            }
            else
            {
                lblStatus.Text = "<font color='red'>Outstanding</font>";
            }
}


Responded is a field in tbl_Enquiries with a Datatype of ‘bit’ (True/False) and is taken from the sqlDataSource Control which grabs all of the records available (no where clauses or anything, just a straight ‘Select * from tbl_Enquiries’).

Would there be a way, with the script suggested, to link up to that field? i.e. I’m thinking in the manner of a reversed way of how its done in the .aspx side - <%#Eval(“Responded”)… so say where ‘responded’ = true then… etc.

Thanks for all your help man, you’ve been real patient with me :slight_smile:

Many Thanks,

Daniel

RESOLVED!

Maybe you can shed light on it.

I took out the else ‘if’ part of the clause:

else if (lblStatus.text = “FALSE”)

  • and its now changing the text as appropriate.

The working code now stands at:

protected void rptGeneralEnq_ItemDataBound(object source, RepeaterItemEventArgs e)
    {
        Label lblStatus = e.Item.FindControl("lblStatus") as Label;

            if (lblStatus != null)
            {
                if (lblStatus.Text == "TRUE")
                {
                    lblStatus.Text = "<font color='green'>Completed</font>";
                }
                else
                {
                    lblStatus.Text = "<font color='red'>Outstanding</font>";
                }
            }
    }

How could something so small be the cause of the problem huh? :stuck_out_tongue:

Thank you so much for all your help and taking your time out, I really appreciate it :slight_smile:

Kindest Regards,

Daniel

That’s essentially 2 ifs. so my guess is that at least sometimes

lblStatus.Text

is not equal to either “True” or “False” but something else.

Hey, no problem. Everyone must learn and start somewhere.

Well, else if (lblStatus.text = “FALSE”) would fail as there is only 1 = instead of 2 ==. But that was probably just a typo here. When comparing strings, you should try to use:

lblStatus.Text.ToLower()==“false” to make sure you are comparing the correct values and not comparing False to FALSE. If you catch my drift. lol

Another bit of advice. You would not want to use select * for your query. It is bad for performance for 2 reasons.

  1. You are might be selecting extra columns == extra data == extra to travel across the wire.

  2. (The main reason) using select * instead of each column, will prevent the database from using its indexes for looking up data in the table, which is a big performance hit. It would be like you trying to get names and number from a phone book that is not in alphabetical order. As you could imagine, it could take quite long. lol

I totally understand on the string front - typo on the Operator and with strings it has to be exact or it will fail - as I found it, i’ll start using the .toLower() method in future, for good practice if nothing else.

I’m aware of the performance hits on sql queries and to be precise enough (which I need to be more thorough about too). The sql statement in this instance requries all fields to show on the front-end, so i just stook to a standard ‘*’.

Many thanks

Dan

Hi, sorry to do this. I’ve over-jumped the gun and on further testing it turns out it doesn’t work.

From what I can make out via Debug Mode is the when the page loads the value that is passed in the ItemDataBound of lblStatus.text is just “”, which is not null (meeting the criteria for the first if) then, as it has no text - true OR false - skips to the else and prints ‘Outstanding’, and not the value per record.

In addition, The first ‘if’ in the script, when I hover over lblStatus the AssociatedControlID = “”. Could this be the problem as it has not found the label?

A couple resolutions of what I thought, but unsure of how to construct, were to refer back to the foreach or create a LINQ to SQL method and within that have the foreach… 'if lblstatus.text == etc. (in the results - which would just be all records anyway). Reason I mention the latter is maybe it would ensure better than the output would be the desired one? Any Ideas?

Again, my greatest apologies,

Regards,

Daniel

Resolved…

protected void rptGeneralEnq_ItemDataBound(object source, RepeaterItemEventArgs e)
{
Label lblStatus = e.Item.FindControl(“lblStatus”) as Label;

    if (DataBinder.Eval(e.Item.DataItem, "Responded").Equals(true))
    {
        if (lblStatus != null)
        {
            if (lblStatus.Text.ToLower() == "true")
            {
                lblStatus.Text = "&lt;font color='green'&gt;Completed&lt;/font&gt;";
            }
            else
            {
                lblStatus.Text = "&lt;font color='red'&gt;Outstanding&lt;/font&gt;";
            }
        }
    }
}