Display Dynamic Content in Listview

Hello,

We have a data source populated which consists of all pro teams across multiple leagues. Every team list record has properties depicting the league, conference and division they belong to.  The list is ordered by league then conference and then division so they are already in the correct order we want them displayed in.  

We are trying to dynamically build a page to not only display all the teams but to dynamically interject headers into it when the division or conference or league changes.  This is proving to be difficult because we are having a hard time detecting when these changes occur and when the do, how to display a header row dynamically.  

1. We aren't sure how one would be able to tell when the league, conference and/or division change from one record to the next. We have an overridden ItemDataBound that is hit on each list record but since its an event, we aren't sure how to trap the league, conference and division from the previous record in order to tell it was changed.  Any ideas???

2. Then, once we have figured out how to determine when one or all of them has changed, how do we dynamically inject new header, we aren't sure how to do this.  The ItemTemplate has a set number of elements to display but we only want these headers to display on certain occasions, basically when we say during the ItemDataBound event.

So picture a class object list with the following properties:

team name, team key, sport, league, conference, division;



We are trying to get the following display:

National Football League (league header)

         American Football Conference (conference header)
                   
                       AFC North  (division header)

                      Team 1  ....................  Stats Link ........... Roster Link ...............
                      Team 2  ....................  Stats Link ........... Roster Link ...............
                      Team 3  ....................  Stats Link ........... Roster Link ...............
                      Team 4  ....................  Stats Link ........... Roster Link ...............

                      AFC South (division header)
                     
                      etc........

Major League Baseball  (league header)

           American League (conference header)

                     East (division header)

                      Team 1  ....................  Stats Link ........... Roster Link ...............
                      Team 2  ....................  Stats Link ........... Roster Link ...............
                      Team 3  ....................  Stats Link ........... Roster Link ...............

                      etc......


As you can see, the number of teams in a division, the number of divisions in a conference and what conferences and leagues are unknown to the template.  So we can't use the GroupTemplate of a Listview since we don't know the value to pass the GroupItemCount.

Does anybody have any good ideas on how our two objectives can be accomplished?  Looking for some specific details, maybe snippet or flow of both front-end control and back-end method.  


Please help.  Thanks.
LVL 4
kruegersteAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

NazoUKCommented:
What kind of datasource are you using? This kind of thing can be done quite nicely with the grouping features of Linq and nested repeaters, however this approach only really works if working with strongly typed objects, not sure how it would go if using sql data directly.
kruegersteAuthor Commented:
Our datasource is a custom class object, see snippet, so it should suffice for what you are looking for.  Its fully populated with everything we need.  We override one of the DataBound methods to case the object back to the correct datatype in order to manually populate the ItemTemplate fields.




    public class TeamsSportsInfo
    {
        //[teams] table
        public Int32  Id { get; set; }         
        public String Key { get; set; }                                                         
        public Int32  PublisherId { get; set; } 
        public Int32  HomeSiteId { get; set; } 

        //other class objects needed for teams
        public AffiliationSportsInfo AffiliationSportsInfo { get; set; }
        public DisplayNamesSportsInfo DisplayNamesSportsInfo { get; set; }
        public ParticipantsEventsSportsInfo ParticipantsEventsSportsInfo { get; set; }
    }

Open in new window

NazoUKCommented:
OK, I knocked up a simple demo. It doesn't use your class definition but it should be simple enough for you to adapt it to your needs:

Simple Data Class:

public class TeamInfo
    {
        public string TeamName { get; set; }
        public string LeagueName { get; set; }
        public string Conference { get; set; }
        public string Division { get; set; }

        public static List<TeamInfo> GetTeams()
        {
            List<TeamInfo> t = new List<TeamInfo>();
            t.Add(new TeamInfo() { TeamName = "Team1", LeagueName = "National Football League", Conference = "American Football Conference", Division = "AFC North" });
            t.Add(new TeamInfo() { TeamName = "Team2", LeagueName = "National Football League", Conference = "American Football Conference", Division = "AFC North" });
            t.Add(new TeamInfo() { TeamName = "Team3", LeagueName = "National Football League", Conference = "American Football Conference", Division = "AFC North" });
            t.Add(new TeamInfo() { TeamName = "Team4", LeagueName = "National Football League", Conference = "American Football Conference", Division = "AFC North" });
            t.Add(new TeamInfo() { TeamName = "Team5", LeagueName = "National Football League", Conference = "American Football Conference", Division = "AFC South" });
            t.Add(new TeamInfo() { TeamName = "Team6", LeagueName = "National Football League", Conference = "American Football Conference", Division = "AFC South" });
            t.Add(new TeamInfo() { TeamName = "Team7", LeagueName = "National Football League", Conference = "American Football Conference", Division = "AFC South" });
            t.Add(new TeamInfo() { TeamName = "Team8", LeagueName = "National Football League", Conference = "American Football Conference", Division = "AFC South" });

            t.Add(new TeamInfo() { TeamName = "Team1", LeagueName = "Major League Baseball", Conference = "American League", Division = "East" });
            t.Add(new TeamInfo() { TeamName = "Team2", LeagueName = "Major League Baseball", Conference = "American League", Division = "East" });
            t.Add(new TeamInfo() { TeamName = "Team3", LeagueName = "Major League Baseball", Conference = "American League", Division = "East" });
            t.Add(new TeamInfo() { TeamName = "Team4", LeagueName = "Major League Baseball", Conference = "American League", Division = "East" });
            t.Add(new TeamInfo() { TeamName = "Team5", LeagueName = "Major League Baseball", Conference = "American League", Division = "West" });
            t.Add(new TeamInfo() { TeamName = "Team6", LeagueName = "Major League Baseball", Conference = "American League", Division = "West" });
            t.Add(new TeamInfo() { TeamName = "Team7", LeagueName = "Major League Baseball", Conference = "American League", Division = "West" });
            t.Add(new TeamInfo() { TeamName = "Team8", LeagueName = "Major League Baseball", Conference = "American League", Division = "West" });

            return t;
        }
    }

ASPX:

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Repeater runat="server" ID="rptLeague" OnItemDataBound="rptLeague_DataBound">
            <ItemTemplate>                
                <h2><%#Eval("Key") %></h2>
                <asp:Repeater runat="server" ID="rptConference" OnItemDataBound="rptConference_DataBound">
                    <ItemTemplate>
                        <div style="padding-left:50px;">
                        <h2><%#Eval("Key") %></h2>
                        <asp:Repeater runat="server" ID="rptDivision" OnItemDataBound="rptDivision_DataBound">
                            <ItemTemplate>
                                <div style="padding-left:100px;">
                                <h2><%#Eval("Key") %></h2>
                                <asp:Repeater runat="server" ID="rptTeams">
                                    <ItemTemplate>
                                        <%#Eval("TeamName") %><br />
                                    </ItemTemplate>
                                </asp:Repeater>
                                </div>
                            </ItemTemplate>
                        </asp:Repeater>
                        </div>
                    </ItemTemplate>
                </asp:Repeater>                
            </ItemTemplate>
        </asp:Repeater>
    </div>
    </form>
</body>
</html>

Code Behind:

protected void Page_Load(object sender, EventArgs e)
        {
            List<TeamInfo> teams = TeamInfo.GetTeams();
            var leaguedTeams = teams.GroupBy(t => t.LeagueName);
            rptLeague.DataSource = leaguedTeams;
            rptLeague.DataBind();
        }

        protected void rptLeague_DataBound(object sender, RepeaterItemEventArgs e)
        {
            IGrouping<string, TeamInfo> leagueData = (IGrouping<string, TeamInfo>)e.Item.DataItem;
            var conferenceData = leagueData.GroupBy(l => l.Conference);
            Repeater rptConference = e.Item.FindControl("rptConference") as Repeater;
            rptConference.DataSource = conferenceData;
            rptConference.DataBind();
        }

        protected void rptConference_DataBound(object sender, RepeaterItemEventArgs e)
        {
            IGrouping<string, TeamInfo> conferenceData = (IGrouping<string, TeamInfo>)e.Item.DataItem;
            var divisionData = conferenceData.GroupBy(c => c.Division);
            Repeater rptDivision = e.Item.FindControl("rptDivision") as Repeater;
            rptDivision.DataSource = divisionData;
            rptDivision.DataBind();
        }

        protected void rptDivision_DataBound(object sender, RepeaterItemEventArgs e)
        {            
            IGrouping<string, TeamInfo> divisionData = (IGrouping<string, TeamInfo>)e.Item.DataItem;
            Repeater rptTeams = e.Item.FindControl("rptTeams") as Repeater;
            rptTeams.DataSource = divisionData;
            rptTeams.DataBind();
        }

Open in new window

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
OWASP: Avoiding Hacker Tricks

Learn to build secure applications from the mindset of the hacker and avoid being exploited.

kruegersteAuthor Commented:
Absolutely awesome.  Worked perfectly and it is exactly what we are looking for.  We will definitely be able to expand on this, thanks for the great start and such a detailed example.  You are a rockstar!!
kruegersteAuthor Commented:
Rockstar!!
kruegersteAuthor Commented:
Hello NazoUk,

Actually, the only obstacle I have run into with this solution is that all the class objects are not available in the league, conference and division repeaters.  The names for all of these plus sports is inside the DisplayNameSportsInfo class object which is inside TeamsSportsInfo

I'm assuming it is because you create a var object to do the LING lambda expression and then assign that to the datasource.  When that happens, only id, key, publisherid and homesiteid are accessible which are the only properties in this class outside of the other classes.

Any ideas how to gain access back into those objects?  It works just fine for the Team repeater because there is no var object or LINQ used.  We tried to cast the var objects back to TeamsSportsInfo type before assigning as datasource but that didn't work.  
 <div>
        <asp:Repeater runat="server" ID="rptLeague" OnItemDataBound="rptLeague_DataBound">
            <ItemTemplate>                
                <h2><%#Eval("DisplayNamesSportsInfo.FullName")%></h2>
                <asp:Repeater runat="server" ID="rptConference" OnItemDataBound="rptConference_DataBound">
                    <ItemTemplate>
                        <div style="padding-left:50px;">
                        <h2><%#Eval("DisplayNamesSportsInfo.FullName")%></h2>
                        <asp:Repeater runat="server" ID="rptDivision" OnItemDataBound="rptDivision_DataBound">
                            <ItemTemplate>
                                <div style="padding-left:100px;">
                                <h2><%#Eval("DisplayNamesSportsInfo.FullName")%></h2>
                                <asp:Repeater runat="server" ID="rptTeams">
                                    <ItemTemplate>
                                        <%#Eval("DisplayNamesSportsInfo.FullName")%><br />
                                    </ItemTemplate>
                                </asp:Repeater>
                                </div>
                            </ItemTemplate>
                        </asp:Repeater>
                        </div>
                    </ItemTemplate>
                </asp:Repeater>                
            </ItemTemplate>
        </asp:Repeater>
    </div>








  protected void Page_Load(object sender, EventArgs e)
        {
            if (IsPostBack == false)
            {
                TeamsSportsBF teamsSportsBF = new TeamsSportsBF();
                List<TeamsSportsInfo> listTeamsSportsInfo = teamsSportsBF.SelectTeamsList("sport_fullname, league_fullname, conf_fullname, div_fullname");

                var leaguedTeams = listTeamsSportsInfo.GroupBy(t => t.AffiliationSportsInfo.LeagueAffiliationKey);
                rptLeague.DataSource = (TeamsSportsInfo)leaguedTeams;
                rptLeague.DataBind();
            }
        }

        protected void rptLeague_DataBound(object sender, RepeaterItemEventArgs e)
        {
            IGrouping<string, TeamsSportsInfo> leagueData = (IGrouping<string, TeamsSportsInfo>)e.Item.DataItem;
            var conferenceData = leagueData.GroupBy(l => l.AffiliationSportsInfo.ConfAffiliationKey);
            Repeater rptConference = e.Item.FindControl("rptConference") as Repeater;
            rptConference.DataSource = (TeamsSportsInfo)conferenceData;
            rptConference.DataBind();
        }

        protected void rptConference_DataBound(object sender, RepeaterItemEventArgs e)
        {
            IGrouping<string, TeamsSportsInfo> conferenceData = (IGrouping<string, TeamsSportsInfo>)e.Item.DataItem;
            var divisionData = conferenceData.GroupBy(c => c.AffiliationSportsInfo.DivAffiliationKey);
            Repeater rptDivision = e.Item.FindControl("rptDivision") as Repeater;
            rptDivision.DataSource = (TeamsSportsInfo)divisionData;
            rptDivision.DataBind();
        }

        protected void rptDivision_DataBound(object sender, RepeaterItemEventArgs e)
        {
            IGrouping<string, TeamsSportsInfo> divisionData = (IGrouping<string, TeamsSportsInfo>)e.Item.DataItem;
            Repeater rptTeams = e.Item.FindControl("rptTeams") as Repeater;
            rptTeams.DataSource = divisionData;
            rptTeams.DataBind();
        }

Open in new window

kruegersteAuthor Commented:
NazoUk,

Is there a way to GroupBy one value but still make all the values available.  It seems whatever value I group by, it is assigned to a Key property.  I would like to GroupBy AffilaitionsSportsInfo.Key but be able to display DispalyNamesSportsInfo.FullName

Any thoughts? Please help.
kruegersteAuthor Commented:
Also, once I attach the initial var datasource in Page_Load, is there any way to cast that object back inside the Repeater methods?  I can't seem to get access to all the original class object property values after the initial LINQ query.  

Hopefully you are still out there.  I can post another question on this if you like.  

Thanks.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
ASP.NET

From novice to tech pro — start learning today.