domingo, 14 de fevereiro de 2010

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

Pessoal, imagine a seguinte situação, você tem uma lista de um determinado objeto e cada objeto dessa lista tem uma propriedade que é 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, 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:

///

/// Classe mãe

///

public abstract class Pessoa

{

private string _nome = string.Empty;

public string Nome

{

get { return _nome; }

set { _nome = value; }

}

public Pessoa() { }

}

///

/// Professor implementa Pessoa

///

public class Professor : Pessoa

{

private string _materia = string.Empty;

public string Materia

{

get { return _materia; }

set { _materia = value; }

}

///

/// Um professor tem uma lista de alunos

///

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;

}

}

///

/// Aluno implementa Pessoa

///

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 pagina.

Primeiro vamos criar um Repeater na pagina 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>

Nometd>

<td>

Cursotd>

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 pagina 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. bem, ai vai depender da necessidade de cada projeto.

Espero ter contribuído com esse artigo.

Nenhum comentário: