views:

3811

answers:

8

I have an ASP.NET page that uses a repeater nested within another repeater to generate a listing of data. It's to the effect of the following:

<asp:Repeater>
    <ItemTemplate>
        <span><%#Eval("Data1") %></span>
        <!-- and many more -->
        <asp:Repeater DataSource='<%#Eval("Data2")%>'>
            <HeaderTemplate>
                <ul>
            </HeaderTemplate>
            <ItemTemplate>
                <li><%#Container.DataItem%></li>
            </ItemTemplate>
            <FooterTemplate>
                </ul>
            </FooterTemplate>
        </asp:Repeater>
    </ItemTemplate>
</asp:Repeater>

In the (C#) code-behind I'm basically using LINQ to pull a listing of information from an XML document and bind that information to the first repeater.

Searching for the answer to this, it seems the method is to determine whether the data for the nested repeater is empty. If it is, then you set the visibility of the repeater to false.

Unfortunately, I haven't been able to determine how to do that inline, and not in the code-behind (since it won't necessarily work for what I'm doing).

Since my pages aren't validating now, because the ul ends up being empty for any items without Data2, and because I'd like to keep using an unordered list, I seek your help.

Any ideas?

Thanks!

UPDATE:

If it helps, since it could very well be possible to do in the code-behind, the LINQ is something to this effect:

var x = from y in z
    select new {
        Data1 = d,
        // etcetera
        Data2 = (from j in k
            where j.Value != String.Empty
            select j.Value).ToList()
    };

blah.DataSource = x;
blah.DataBind();
A: 

When you get your LINQ query executed, check its Count property (providing its a list of some sort). If its 0, then just turn the Visible property to false.

That's in the code-behind... not "inline" like he asked for. I was about to say the same thing, then I read a little closer :)
Timothy Khouri
In case it is possible, I've added the LINQ to the original question.
James Skemp
A: 

As far as I know you must do this via the codebehind, just use the ItemDataBound event to handle it, you can leave pretty much everything as is, just simply input some logic that gets the dataset and determines if it has entries, if not hide the repeater.

Mitchel Sellers
A: 

Try something like:

<asp:Repeater runat="server" DataSource='<%#Eval("Data2")%>' 
    Visible='<%# ((IEnumerable)Eval("Data2")).GetEnumerator().MoveNext() %>'>

for the nested repeater

Aleris
A: 

I don't think what you are doing is going to work I get an error when I try and set the DataSource as you are trying to do; however, in the code behind you do this:

Assuming you added a listener to your parent repeater's ItemDataBoundEvent, then you will need to change your linq query slightly to not use an anonymous type (Create a protected class that has your properties) In mjy case I am using dto as the class name.

void rep1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{

    Repeater rep2 = (Repeater)e.Item.FindControl("rep2");
    rep2.DataSource = ((dto)e.Item.DataItem).y;
    rep2.DataBind();
}

I'd love to learn why you think you can't solve this in the code behind.

JoshBerke
+4  A: 

This won't hide the repeater completely, but you can subclass the Repeater control so that it includes a GridView-like empty data template:

using System;
using System.Web.UI;
using System.Web.UI.WebControls;

public class EmptyCapableRepeater : Repeater
{
    public ITemplate EmptyDataTemplate { get; set; }

    protected override void OnDataBinding ( EventArgs e )
    {
        base.OnDataBinding( e );

        if ( this.Items.Count == 0 )
        {
            EmptyDataTemplate.InstantiateIn( this );
        }
    }
}

You can them use it in your .aspx like this:

<custom:EmptyCapableRepeater runat="server" ID="rptSearchResults">
    <ItemTemplate>
        <%# Eval( "Result" )%>
    </ItemTemplate>
    <SeparatorTemplate>
        <br />
    </SeparatorTemplate>
    <EmptyDataTemplate>
        <em>No results were found.</em>
    </EmptyDataTemplate>
</custom:EmptyCapableRepeater>
Matt Peterson
A: 

Why not use a ListView? It offers much of the same functionality including an EmptyDataTemplate.

Michael Silver
Good question :)I believe I was targeting to .NET Framework 2.0 at the time.
James Skemp
A: 

I know this is an old thread and the answer above is a very nice solution, but I had a similar problem and have found another vary simple solution I thought I would share also. This validates just fine and displays the same.

Just change your footer template to:

<FooterTemplate> 
            <li style="display:none;">This will not show.</li></ul> 
</FooterTemplate> 

Or if your using tables:

<FooterTemplate> 
            <tr> style="display:none;"><td>But something must be in here.</td></tr></table> 
</FooterTemplate> 

Hope that helps someone!

Thanks for sharing.
James Skemp
A: 

In the OnItemDataBound event, set visibility to false if ItemType is a Header and set visibility to true if ItemType is an Item.

Brian