Desenvolvimento

5 mar, 2010

Repeater dentro de Repeater (DataList dentro de DataList ou GridView dentro de GridView)

Publicidade

Imagine a seguinte situação: você tem uma lista de um determinado
objeto e cada objeto dessa lista tem uma propriedade. Essa propriedade é uma lista
de um determinado objeto e você precisa popular um Repeater.

Vamos
dar nomes aos objetos: suponha que você tenha uma lista de
professores e cada professor tem seus alunos, bem, alguns irão
dizer que é fácil, cada vez que o Repeater fizer um ItemDataBound basta
fazer um busca novamente no banco de dados e listar o resultado. Como
sempre me deparo com essa situação e vira e mexe algum me pergunta
se essa é a melhor maneira de fazer resolvi escrever um artigo.

É
muito simples, se a sua coleção já vem populada, basta você passar
essa lista de objetos para o outro controle dentro do seu Repater
(nesse caso outro Repeater), e isso será feito a cada ItemDataBound.

Classes

Temos
as seguintes classes:

/// <summary>
/// Classe mãe
/// </summary>
public abstract class Pessoa
{
private string _nome = string.Empty;
public string Nome
{
get { return _nome; }
set { _nome = value; }
}
public Pessoa() { }
}
/// <summary>
/// Professor implementa Pessoa
/// </summary>
public class Professor : Pessoa
{
private string _materia = string.Empty;
public string Materia
{
get { return _materia; }
set { _materia = value; }
}
/// <summary>
/// Um professor tem uma lista de alunos
/// </summary>
private System.Collections.Generic.List<Aluno> alunos = new System.Collections.Generic.List<Aluno>();
public System.Collections.Generic.List<Aluno> Alunos
{
get { return alunos; }
set { alunos = value; }
}
public Professor(string nome, string materia, System.Collections.Generic.List<Aluno> alunos)
{
Nome = nome;
Materia = materia;
Alunos = alunos;
}
}
/// <summary>
/// Aluno implementa Pessoa
/// </summary>
public class Aluno : Pessoa
{
private string _turma = string.Empty;
public string Turma
{
get { return _turma; }
set { _turma = value; }
}
public Aluno(string nome, string turma)
{
Nome = nome;
Turma = turma;
}
}

WebForm

Agora
que já conhecemos nossas classes vamos para a implementação disso
em uma página. Primeiro
vamos criar um Repeater na página e, dentro dele, criaremos um segundo
repeater, como no exemplo abaixo:

<asp:Repeater ID="ProfessorRepeater" runat="server" OnItemDataBound="ProfessorRepeater_ItemDataBound">
<ItemTemplate>

Professor:
<%# Eval("Nome") %>
<br />

Matéria:
<%# Eval("Materia") %>
<br />

Alunos:
<asp:Repeater ID="AlunoRepeater" runat="server">
<HeaderTemplate>
<table>
<tr style="font-weight: bold">
<td>
Nome</td>

<td>
Curso</td>
</tr>

</HeaderTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
<ItemTemplate>
<tr style="background-color: Gray">
<td>
<%# Eval("Nome") %>
</td>
<td>
<%# Eval("Turma")%>
</td>
</tr>
</ItemTemplate>
<AlternatingItemTemplate>
<tr style="background-color: Silver">
<td>
<%# Eval("Nome") %>
</td>
<td>
<%# Eval("Turma") %>
</td>
</tr>
</AlternatingItemTemplate>
</asp:Repeater>
</ItemTemplate>
<SeparatorTemplate>
<hr />
</SeparatorTemplate>
</asp:Repeater>

Atente
para o detalhe que o repeater AlunoRepater está escrevendo as
propriedades Nome (que vem de Pessoa) e turma (que é da classe
Aluno).

Bom, mas isso não irá funcionar dessa maneira. Vejamos no
code behind da página como é a implementação disso.

Code Behind

No
PageLoad os objetos são criados e populados.

protected void Page_Load(object sender, EventArgs e)
{
Page.Title = "Repeater dentro de Repeater (DataList dentro de DataLista ou GridView dentro de GridView)";
// lista de alunos que será atribuída aos professores
List<Aluno> alunosEpaminondas = new List<Aluno>();
alunosEpaminondas.Add(new Aluno("Alan", "Sistemas da Informação"));
alunosEpaminondas.Add(new Aluno("Fabio", "Ciência da Computação"));
alunosEpaminondas.Add(new Aluno("Marcelo", "Desenvolvimento de Sistemas Web"));
// Só para não falar que os professores tem os mesmos alunos
List<Aluno> alunosAdolfo = new List<Aluno>();
alunosAdolfo.Clear();
alunosAdolfo.Add(new Aluno("Carol", "Análise de Sistemas"));
alunosAdolfo.Add(new Aluno("Bruno", "Banco de Dados"));
// lista de professores
List<Professor> professores = new List<Professor>();
professores.Add(new Professor("Epaminondas", "Gestão de Projetos", alunosEpaminondas));
professores.Add(new Professor("Adolfo", "Programação Orientação a Objetos", alunosAdolfo));
ProfessorRepeater.DataSource = professores; // define o DataSource do repeater como a lista de objetos professores
ProfessorRepeater.DataBind();
}

No
controle ProfessorRepeater, no evento ItemDataBound que o controle
AlunoRepeater é populado, veja como é simples fazer a conversão do
item do repeater que é passado.

protected void ProfessorRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
// verifica se o item é do tipo ItemType ou AlternatingItem, se não for retorna e não continua o processamento
if (e.Item.ItemType != ListItemType.Item && e.Item.ItemType != ListItemType.AlternatingItem) return;
// verifica se o objeto AlunoRepeater existe dentro do item
if (e.Item.Controls.Contains((Repeater)e.Item.FindControl("AlunoRepeater")))
{
// cria um objeto Repeater e define-o como o objeto AlunoRepeater do item
Repeater alunoRepeater = (Repeater)e.Item.FindControl("AlunoRepeater");
// converte o item (linha do repeater) para um professor e define a propriedade Alunos como DataSource do repeater
alunoRepeater.DataSource = ((Professor)e.Item.DataItem).Alunos;
alunoRepeater.DataBind();
}
}

Super
simples e tranqüilo, não há segredos nisso. A grande sacada é não
ter que conectar ao banco novamente apenas obter os outros objetos. É
possível utilizar isso também na criação de menus, para exibir a
notas fiscais e seus itens, pedidos e seus itens etc. Aí vai
depender da necessidade de cada projeto.

Até a próxima!