Por vezes temos necessidade de integrar muitos dados num ecrã para os apresentar da forma mais conveniente ao utilizador.
O que acontece durante este processo é que por vezes enfrentamos algumas dificuldades em transpor a informação que temos organizada na camada de negócio para a camada de apresentação de uma forma simples e sem grandes alterações na sua estrutura.
Por exemplo, quando temos uma classe Contacto que além das suas propriedades mais comuns, contém também uma propriedade que é uma estrutura de dados da classe Servico, por vezes a melhor solução é optar por utilizar ListViews encadeadas.
public class Contacto { public int id { get; set; } public string nome { get; set; } public IEnumerable<Servico> servicos { get; set; } public Contacto() { servicos = new List<Servico>(); } public IEnumerable<Contacto> ObterContactos() { for (int i = 0; i < 3; i++) { var c = new Contacto(); c.id = i; c.nome = "nome_" + i; c.servicos = (new Servico()).ObterServicos(i); yield return c; } yield break; } }
Como podem verificar no código apresentado anteriormente, a classe Contacto tem uma propriedade do tipo IEnumerable<Servico>, que é uma estrutura de dados da classe Servico.
public class Servico { public int id { get; set; } public string descricao { get; set; } public IEnumerable<Servico> ObterServicos(int id) { var listaServicos = new List<Servico>(); for (int i = 0; i < 3; i++) { var serv = new Servico(); serv.id = i; serv.descricao = string.Format("servico_{0}_{1}", i, id); listaServicos.Add(serv); } return listaServicos; } }
Numa situação em que temos que apresentar num ecrã a informação da classe Contacto, a melhor solução seria poder alimentar um único controlo com uma lista de elementos desta classe e, este se encarrega-se de agregar a informação.
Sugiro algo assim:
<div> <h2>Exemplo de Nested ListViews</h2> <asp:ListView ID="ListViewPai" runat="server"> <LayoutTemplate> <asp:PlaceHolder runat="server" ID="itemPlaceholder"></asp:PlaceHolder> </LayoutTemplate> <ItemTemplate> <h5>Informacao da ListView Pai</h5> <p>Nome:<%#Eval("nome") %></p> <asp:ListView ID="ListViewFilho" runat="server" DataSource='<%# Eval("servicos") %>'> <LayoutTemplate> <h6>Informacao da ListView Filho</h6> <asp:PlaceHolder runat="server" ID="itemPlaceholder"></asp:PlaceHolder> </LayoutTemplate> <ItemTemplate> <div style="border:1px solid black; width:250px; margin:15px;"> <p>id:<%#Eval("id") %></p> <p>descricao:<%#Eval("descricao") %></p> </div> </ItemTemplate> </asp:ListView> <hr /> </ItemTemplate> </asp:ListView> </div>
Como podem verificar, a fonte de dados que alimenta a ListViewFilho é “<%# Eval("servicos") %>” que é o nome da propriedade existente na classe Contacto e que é do tipo IEnumerable<Servico>.
Ou seja, cada item do ListViewPai vai alimentar o ListViewFilho com a sua propriedade Servico.
O que resulta num código de carregamento de dados extremamente simples, como podemos verificar:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; namespace WebApplication1 { public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { if (!Page.IsPostBack) { CarregarDadosListView(); } } public void CarregarDadosListView() { ListViewPai.DataSource = (new Contacto()).ObterContactos(); ListViewPai.DataBind(); } } }
Ao utilizar este método apenas basta alimentar o datasource da ListViewPai, depois é cada item desta listview quem se encarrega de dar informação a ser apresentada à ListViewFilho.
Faça aqui o download do projecto de demonstração em VS2010