Search This Blog

Accessing controls inside a ListView

posted on Monday, November 5, 2012


So, a friend of mine asked my help with a developing problem he encountered: he had a listview in a listview but in the code behind, he could not access the nested listview. Since I ran into this problem once myself and forums are loading with the same question, it seemed like a good idea to write a blog post about it for those who encounter this issue in the future!

Let's start by explaining why the nested listview is not accessible. I also have a nice example set up for you to show you how it's done.

So, most importantly, why is the nested listview not accessible in the code behind like the parent listview? Well, it's quite logical actually: the parent listview is a unique control that you can access from the code behind using the id just like you can with any other type of control. The difference with the nested listview however is that this listview is not unique... You put it in a listview so it occurs for each item in the listview! If you want to access the nested listview, you'll have to use the specific item that holds the listview that you want to edit!

Below you can find the design code and the code-behind for an example of how it's done:

As you can see, we have two listviews one placed in the item template of the other. They both have labels in their item template as well.

<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true"
    CodeBehind="Default.aspx.cs" Inherits="WebApplication1._Default" >
<asp:content contentplaceholderid="HeadContent" id="HeaderContent" runat="server">
</asp:content>
<asp:content contentplaceholderid="MainContent" id="BodyContent" runat="server">
    <asp:listview id="list" itemplaceholderid="placeHolder" ondatabound="list_DataBound" runat="server">
        <itemtemplate>
            <asp:label font-bold="True" font-size="Large" id="LabelName" runat="server" text="<%#Eval(&quot;FirstName&quot;) %>">
            <asp:listview id="sublist" itemplaceholderid="subPlaceHolder" runat="server">
                <itemtemplate>
                    <asp:label id="LabelCompany" runat="server" text="">>%#Eval("Name") %></asp:label>
                </itemtemplate>
                <layouttemplate>
                    <asp:placeholder id="subPlaceHolder" runat="server"></asp:placeholder>
                </layouttemplate>
            </asp:listview>
        </asp:label></itemtemplate>
        <layouttemplate>
            <asp:placeholder id="placeHolder" runat="server"></asp:placeholder>
        </layouttemplate>
    </asp:listview>
</asp:content>

The code-behind generates lists to fill the listviews. The parent listview is databound when the page loads. The nested listview is databound in the databound action of the parent listview... still with me? :P

So when the parent listview is databound, we'll loop the freshly added items in this listview and for eacht of these items, we'll fill the nested listview approprietly to the contents of the label by using the FindControl method on the listitem. And that's all there is to it! :)

using System;
using System.Collections.Generic;
using System.Web.UI.WebControls;

namespace WebApplication1
{
    public partial class _Default : System.Web.UI.Page
    {
        private List<person> coolPeople; 
        private List<company> gatesCompany;
        private List<company> jobsCompany;

        protected void Page_Load(object sender, EventArgs e)
        {
            coolPeople = new List<person>();
            coolPeople.Add(new Person {FirstName = "Bill", LastName = "Gates"});
            coolPeople.Add(new Person {FirstName = "Steve", LastName = "Jobs"});

            gatesCompany = new List<company>();
            gatesCompany.Add(new Company(){Name = "Microsoft"});
            gatesCompany.Add(new Company(){Name = "Bill & Melinda Gates Foundation"});

            jobsCompany = new List<company>();
            jobsCompany.Add(new Company(){Name = "Apple"});
            jobsCompany.Add(new Company(){Name = "NeXT"});
            jobsCompany.Add(new Company(){Name = "Pixar"});

            list.DataSource = coolPeople;
            list.DataBind();
        }

        protected void list_DataBound(object sender, EventArgs e)
        {
            foreach (var item in list.Items)
            {
                var subList = item.FindControl("sublist") as ListView;

                var name = ((Label) item.FindControl("LabelName")).Text;
                if(name.Equals("Steve"))
                {
                    subList.DataSource = jobsCompany;
                } 
                else
                {
                    subList.DataSource = gatesCompany;
                    
                }

                subList.DataBind();
            }
        }
    }

    public class Person
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }      
    }

    public class Company
    {
        public string Name { get; set; }
    }
}

Oh and for the fans: this is what this wonderful application would like :)


That's all, I hope this example helps you understand the issue and that's it's actually not an issue at all but quite a logical consequence of the listview structure.

Happy coding!


Could be useful, right?

2 comments:

  1. Interesting post, but unfortunately, this does not solve my issue.
    Maybe you can help. I will appreciate it.

    I like to copy the value, which is retrieved in a textbox, which is inside a ListView control, when the page finish loading and retrieving data from an XML file, to another textbox, which is outside the ListView control. Any idea how to do this ?

    ReplyDelete
  2. Hi there!

    This post should help you with the first part of your question (a textbox inside a listview), for the second part maybe this can help: http://stackoverflow.com/questions/7119806/c-sharp-reading-data-from-xml.

    I hope this helps, if not, let me know!

    Kind regards, TCBU.

    ReplyDelete