Data Grid

Embed Size (px)

Citation preview

TUDO SOBRE DATAGRID (ASP

Tutorial - Tudo Sobre DataGrid (ASP.NET e C#)

vs. RTM 1.005/Jun/2002

TUTORIAL

Tudo Sobre DataGrid

(ASP.NET e C#)

N D I C E

4Caso Mais Simples

11Alterando a Interface Visual do DataGrid

Usando a Paginao Atutomtica do DataGrid11Usando a Ordenao do Datagrid14Customizando o DataGrid1642Usando o Conceito de Master/Detail DataGrid

Usando a Ordenao e a Paginao Customizadas no DataGrid32

Introduo

Um dos controles mais poderosos no ASP.NET , sem dvida, o DataGrid, pois a maioria das aplicaes para a web (seno todas) iro, de alguma forma, utilizar este controle. O DataGrid nada mais que uma tabela que permite estabelecer o vnculo com uma fonte de dados (fique atento ao termo fonte de dados que ser explicado mais adiante), apresentando esses dados de forma estruturada.

Esse controle se baseia na utilizao de objetos do HTML, quando estes objetos so renderizados no formato adequado ao computador do cliente, atravs de uma srie de propriedades e mtodos definidos no servidor que resultam na economia de inmeras linhas de cdigo.

Este tutorial tem por objetivo tratar de maneira abrangente tudo o que se refere ao objeto DataGrid. Trataremos, aqui, desde sua implementao mais simples at uma implementao extremamente complexa, que permite a paginao e a ordenao customizadas. Veremos tambm como utilizar um DataGrid, dentro de outro DataGrid (conceito de Master/Detail).

Caso Mais Simples

Veja, a seguir, um dos exemplos mais simples de utilizao de um DataGrid. Supondo que voc esteja em uma pgina vazia aspx, simplesmente crie um objeto DataAdapter no IDE do Visual Studio .NET (VS.NET), escolhendo a query de sua preferncia (fazendo isto com o IDE, ele pode criar, automaticamente, o objeto Connection para a conexo com o banco de dados). Em seguida, gere um DataSet fortemente tipado (Typed Dataset) atravs do objeto DataAdapter criado anteriormente, clicando com o boto direito do mouse e selecionando Generate DataSet. Observe que nada foi escrito at agora; todo o processo foi inteiramente visual!

OBS: Apenas a ttulo de exemplo, neste tutorial estaremos utilizando a tabela Pubs, do SQL Server 2000; a query utilizada na gerao do DataAdapter acima foi a SELECT * FROM Authors.

Insira agora um objeto DataGrid na pgina e selecione a propriedade DataSource no IDE; e observe a opo de seleo do DataSet que foi criada e escolha a mesma. A partir deste momento, o Objeto DataGrid j reconhece os campos da tabela no DataSet. Escolha agora a propriedade DataMember e observe que j possvel escolher authors.

Veja como fica sua pgina com as duas opes selecionadas:

Note que, mais uma vez, nenhuma linha de cdigo foi escrita at agora.

Para que os dados possam ser capturados e o DataSet preenchido com esses dados, seguido pelo DataGrid, vamos colocar apenas o seguinte cdigo no evento load da pgina:

sqlConnection1.Open();

sqlDataAdapter1.Fill(DS_Authors1);

sqlConnection1.Close();

DG_Simples.DataBind();

Agora rode a pgina e veja o resultado:

Observe o que aconteceu:

O Objeto Connection abriu a conexo com o banco de dados; em seguida, o objeto DataAdapter populou o Dataset com os dados do banco de dados, fechando, logo depois, a conexo com esse banco de dados; no passo seguinte, o objeto DataGrid foi populado com os dados do DataSet. Neste momento, a conexo j est desfeita, pois estamos diante do conceito de fonte de dados e no de banco de dados. Para preencher o DataGrid, no h necessidade de conexo a nenhum banco de dados, e sim, a uma fonte de dados. Esta fonte de dados poderia ser, por exemplo, um arquivo XML que teria populado o DataSet.

Trouxemos este exemplo s para mostrar como simples inserir uma tabela de dados no ASP.NET. bvio que esse exemplo to simples tem pouca utilidade prtica, por isso, no prximo item, vamos explorar um pouco mais o objeto DataGrid para mostrar suas propriedades alterando, assim, sua interface visual.

Vamos aos cdigos dos arquivos:

Simples.aspx:

Parte superior do formulrio

Parte inferior do formulrio

Simples

Parte superior do formulrio

Parte inferior do formulrio

Simples.aspx.cs (SEM a parte de cdigo, gerado automaticamente pelo VS.NET):

using System;

using System.Collections;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Web;

using System.Web.SessionState;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Web.UI.HtmlControls;

namespace CoolDataGrid

{

public class Simples : System.Web.UI.Page

{

protected System.Data.SqlClient.SqlDataAdapter sqlDataAdapter1;

protected System.Data.SqlClient.SqlCommand sqlSelectCommand1;

protected System.Data.SqlClient.SqlCommand sqlInsertCommand1;

protected System.Data.SqlClient.SqlCommand sqlUpdateCommand1;

protected System.Data.SqlClient.SqlCommand sqlDeleteCommand1;

protected System.Data.SqlClient.SqlConnection sqlConnection1;

protected CoolDataGrid.DS_Authors DS_Authors1;

protected System.Web.UI.WebControls.DataGrid DG_Simples;

private void Page_Load(object sender, System.EventArgs e)

{

// Abre a conexo e preenche o DataSet com os Dados

// depois fecha a conexo

sqlConnection1.Open();

sqlDataAdapter1.Fill(DS_Authors1);

sqlConnection1.Close();

//Preenche a DataGrid

DG_Simples.DataBind();

}

}

}

Alterando a Interface Visual do DataGrid

Existem diversas propriedades do objeto DataGrid que servem para alterar sua apresentao visual. Veja, por exemplo, como podem ser alteradas as seguintes propriedades do Datagrid, na pgina Simples.aspx (apenas o tag DataGrid):

A tabela fica com a seguinte aparncia:

H outras propriedades de estilo muito importantes. So elas:

AlternatingItemStyle

Propriedade usada para alterar o estilo da aparncia das linhas alternadas (pares) do DataGrid.

EditItemStyle

Propriedade usada para alterar o estilo da aparncia da linha que se encontra em modo de edio.

FooterStyle

Propriedade usada para alterar o estilo da aparncia da linha de rodap do DataGrid.

HeaderStyle

Propriedade usada para alterar o estilo da aparncia da linha de cabealho do DataGrid.

ItemStyle

Propriedade usada para alterar o estilo da aparncia das linhas Alternadas (mpares) do DataGrid.

PageStyle

Altera o estilo da aparncia dos objetos de paginao automtica do DataGrid.

SelectedItemStyle

Propriedade usada para alterar o estilo da aparncia da linha do DataGrid selecionada (apenas quando utilizado com um objeto de seleo de linha, como, por exemplo, um boto).

No exemplo abaixo, os itens Header, Item e AlternatingItem iro mudar apenas algumas cores e estilos de fontes destes elementos:

OBS: a mesma padronizao poderia ser feita com Tags Styles, pois possvel utilizar objetos Styles do HTML para trabalhar com os grids. Assim, poderamos ter o mesmo resultado que o obtido acima, com a seguinte pgina Simples.aspx:

Simples

.table { FONT: x-small Tahoma; COLOR: navy }

.tableItem {FONT: x-small Tahoma; COLOR: navy; BACKGROUND-COLOR: floralwhite}

.tableHeader {FONT: x-small Tahoma; COLOR: black; BACKGROUND-COLOR: darkseagreen; FONT-WEIGHT: Bold}

.alternatingItem {FONT: x-small Tahoma; COLOR: navy; BACKGROUND-COLOR: silver}

Usando a Paginao Automtica do DataGrid

Com a paginao o programador j comea a utilizar um pouco mais de cdigo, mas, sem dvida, nada que se compare aos processos de antigamente.

Suponha, agora, que o resultado desta query fosse um registro enorme, com uma sucesso interminvel de linhas. Certamente, a pgina ficaria extremamente lenta, o que nos obrigaria a recorrer criao de uma paginao. O objeto DataGrid j vem com um exemplo de paginao embutido que utiliza os recursos de paginao. Para isto, recorre-se a 3 propriedades do objeto DataGrid: PageSize, AllowPaging, e AllowCustomPaging.

Vejamos como isso ocorre:

Por default, a propriedade AllowPaging False; temos, ento, que configur-la com True. A propriedade-padro do PageSize 10, portanto, neste exemplo, vamos configur-la como 5, para manter as pginas construdas com a mesma query utilizada anteriormente. Por enquanto deixemos AllowCustomPaging sem nada.

Agora, basta criar o evento que cuidar da paginao, que o evento OnPageIndexChanged. Este evento dever apontar para um mtodo no seu cdigo, como no exemplo abaixo:

Na pgina Simples.aspx (apenas as propriedades do DataGrid):

OnPageIndexChanged="AlteraPagina"

Na Pgina Simples.aspx.cs (apenas os mtodos da classe):

private void Page_Load(object sender, System.EventArgs e)

{

//verifica se um submit para mesma pgina (PostBack)

if (!IsPostBack)

{

BindData();

}

}

protected void BindData()

{

// Abre a conexo e preenche o DataSet com os Dados

// depois fecha a conexo

sqlConnection1.Open();

sqlDataAdapter1.Fill(DS_Authors1);

sqlConnection1.Close();

//Preenche a DataGrid

DG_Simples.DataBind();

}

protected void AlteraPage(Object sender, DataGridPageChangedEventArgs e)

{

//configura nova pgina

DG_Simples.CurrentPageIndex=e.NewPageIndex;

BindData();

}

O evento load da pgina verifica apenas se est ocorrendo uma primeira chamada nesta pgina ou se um PostBack, que significa um submit da pgina para ela mesma. Caso no seja um PostBack, o evento preenche os dados do DataGrid com a rotina Bind.

Em seguida, o evento que cuida da paginao adapta e devolve o ndice da pgina e, com o mtodo Bind, a pgina recarrega os dados.

Veja o resultado dessa tarefa e teste a paginao:

A paginao ocorreu com os caracteres , para frente e para trs, mas pode-se alterar este formato com as propriedades de estilo do PagerSyle:

Existem dois tipos bsicos definidos pela propriedade Mode: NextPrev e NumericPages. O primeiro define paginao em texto, e o segundo, paginao em nmero. Vejamos um exemplo de cada, analisando primeiramente a paginao em texto:

Defina a propriedade Mode como NextPrev, e depois defina as seguintes propriedades (que s se aplicam para este Mode):

Veja o resultado:

Vejamos , agora o exemplo da paginao com Nmeros: defina a propriedade Mode como NumericPages e defina as seguintes propriedades (somente para o Style PagerStyle):

Veja o resultado:

OBS: tome muito cuidado com o recurso de paginao automtica do DataGrid. Ele s recomendado para pequenas quantidades de dados, pois a cada mudana de pgina feita uma busca do TODOS os dados junto ao banco de dados. Se o nmero de dados for muito grande, deve-se utilizar uma lgica de paginao customizada, como veremos mais adiante.

Usando a Ordenao do DataGrid

O uso de ordenao pressupe que a montagem da busca da query seja dinmica, ou seja, a ordenao requer a utilizao de uma clusula ORDER BY dinmica na coleta dos dados para a pgina, com o uso da propriedade SortExpression de cada coluna do DataGrid.

Para que possamos alterar dinamicamente a chamada da query, vamos incluir uma varivel string e coloc-la no objeto selectcommand do DataAdapter que foi utilizado at agora. Em seguida, iremos alterar o mtodo BindData para que ele reflita essa ordenao.

Vamos tambm incluir o novo mtodo de ordenao AlteraSort, definido na propriedade do DataGrid OnSortCommand, e configur-lo como AllowSorting = True. Analisemos os cdigos da pgina:

Simples.aspx (s a tag DataGrid):

Simples.aspx.cs:

public class Simples : System.Web.UI.Page

{

protected System.Data.SqlClient.SqlDataAdapter sqlDataAdapter1;

protected System.Data.SqlClient.SqlCommand sqlSelectCommand1;

protected System.Data.SqlClient.SqlCommand sqlInsertCommand1;

protected System.Data.SqlClient.SqlCommand sqlUpdateCommand1;

protected System.Data.SqlClient.SqlCommand sqlDeleteCommand1;

protected System.Data.SqlClient.SqlConnection sqlConnection1;

protected CoolDataGrid.DS_Authors DS_Authors1;

protected System.Web.UI.WebControls.DataGrid DG_Simples;

protected string strSQL = "SELECT * FROM authors";

private void Page_Load(object sender, System.EventArgs e)

{

//verifica se um submit para mesma pgina (PostBack)

if (!IsPostBack)

{

BindData();

}

}

protected void BindData()

{

// Abre a conexo e preenche o DataSet com os Dados

// depois fecha a conexo

sqlConnection1.Open();

this.sqlSelectCommand1.CommandText = strSQL;

sqlDataAdapter1.Fill(DS_Authors1);

sqlConnection1.Close();

//Preenche a DataGrid

DG_Simples.DataBind();

}

protected void AlteraPage(Object sender, DataGridPageChangedEventArgs e)

{

//configura nova pgina

DG_Simples.CurrentPageIndex=e.NewPageIndex;

BindData();

}

protected void AlteraSort(Object sender,DataGridSortCommandEventArgs e)

{

strSQL = strSQL + " ORDER BY " + e.SortExpression;

BindData();

}

}

Vejamos o resultado:

Simples, no? Agora, basta clicar em qualquer cabealho da tabela acima para orden-la automaticamente.

Customizando o DataGrid

Tudo o que foi feito at agora pode parecer muito interessante, mas ainda nos vemos diante de algumas limitaes. Por exemplo, no foi possvel customizar uma coluna em saparado, pois o DataGrid fez tudo automaticamente. Entretanto, existe uma maneira para trabalhar cada coluna e cada linha do DataGrid com o uso do tag . Uma forma de fazer isso alterar a propriedade AutoGenerateColumns para False (o padro True), para que voc mesmo possa inserir coluna por coluna no DataGrid, fornecendo assim, as informaes customizadas de sua preferncia, definindo cada coluna do DataGrid.

Existem 5 tipos de Colunas do DataGrid:

BoundColumn

Permite a insero de uma coluna diretamente vinculada a um campo da fonte de dados.

ButtonColumn

Permite a insero de uma coluna de disparo de evento, podendo este evento estar vinculado a um campo da fonte de dados.

EditCommandColumn

Permite a insero de um boto de comando para cada linha de uma coluna para coloc-la em modo de edio.

HyperLinkColumn

Permite a insero de um link para cada linha da coluna, mantendo-odiretamente vinculado a um campo da fonte de dados.

TemplateColumn

Permite a insero de uma linha completamente customizada em HTML, mantendo-ovinculado a qualquer campo da fonte de dados.

OBS: No h necessidade de colocar a varivel AutoGenerateColumns como False para utilizar os itens de colunas verificados acima; o que ocorreria que esses itens seriam adicionados, caso a opo de AutoGenerateColumns fosse True.

A seguir, analisemos um exemplo para cada tipo de coluna:

Exemplo BoundColumns

Neste exemplo, vamos retirar a propriedade de auto-gerao de campos do DataGrid, e vamos criar, por enquanto, todos os campos resgatados na query (para simplificar o trabalho vamos manter a pgina Simples.aspx, embora seria recomendvel comear com outra pgina, para efeito comparativo):

Arquivo Simples.aspx (completo):

Simples

.table { FONT: x-small Tahoma; COLOR: navy }

.tableItem { FONT: x-small Tahoma; COLOR: navy; BACKGROUND-COLOR: floralwhite }

.tableHeader { FONT: bold x-small Tahoma; COLOR: black; BACKGROUND-COLOR: darkseagreen }

.alternatingItem { FONT: x-small Tahoma; COLOR: navy; BACKGROUND-COLOR: silver }

Arquivo Simples.aspx.cs (NO se Altera).

OBS: possvel inserir diretamente a parte Columns do arquivo aspx, de forma manual, ou utilizar o prprio IDE do VS.NET para fazer a tarefa visualmente, bastando, para isso, selecionar o DataGrid em modo Design e clicar em Collections da propriedade Columns. Aparecer uma janela de configurao de colunas na qual ser possvel inserir todos os campos, automaticamente, ou configurar um a um. Em seguida, ser possvel configurar cada item da seleo (veja imagem abaixo com um dos itens selecionados). Esta opo muito poderosa no que diz respeito velocidade de programao e at mesmo ao controle de qualidade, pois a chance de se errar um cdigo, ao escrev-lo muito maior do que se o IDE fizer tudo automaticamente.

Veja o resultado:

Podemos observar que existe uma srie de configuraes. Entre elas, podemos citar:

Visible

Mostra ou no a coluna (muito til com campos de chave primria, pois, embora no precisem aparecer, eles tem que ser armazenados nas linhas).

SortExpression

Expresso que ser enviada ao objeto de eventhandler que ser disparado quando da ordenao (pode ser qualquer campo da fonte de dados, no havendo necessidade de ser o campo da coluna propriamente dito).

ReadOnly

Define a coluna como no-editvel (utilizada quando a linha colocada em modo de edio deixando esta coluna como ReadOnly. Este tpico ser abordado mais adiante, em detalhes).

HeaderText e HeaderImageDefine a apresentao que ser dada ao cabealho da coluna.

FooterText

Idem ao anterior, s que no rodap (apenas quando o rodap estivervisvel, pois o padro False).

DataFormatingExpression

Utilizado para formatar campos com tipos pr-definidos, como, por exemplo, um valor em formato Currency.

Tambm possvel definir as colunas para que elas apaream somente em tempo de execuo, embora isso no compense, em matria de performance, valendo apenas em exemplos com colunas ainda customizadas, como veremos mais adiante.

OBS: Ainda para o BoundColumn (mas vale para QUALQUER coluna), existe tambm a propriedade Width de cada coluna (tambm acessada pela Colllections) Esta opo pode igualmente ser encontrada quando da definio das colunas, selecionando o item Format e no Columns esquerda da janela (veja figura abaixo):

Exemplo EditCommandColumn, ButtonColumn e HyperLynkColumn

Neste exemplo, vamos inserir 3 novas colunas. Cada uma ir utilizar os trs tipos de botes acima.

Para a coluna EditCommandColumn, as propriedades importantes so:

ButtonType Define o tipo de boto;

HeaderText Define o texto do cabealho;

EditText Define o texto que ir disparar a edio da linha (mtodo definido na propriedade OnEditCommand do DataGrid);

UpdateText Define o texto que ir disparar a atualizao da linha (mtodo definido na propriedade OnUpdateCommand do DataGrid);

CancelText Define o texto que ir disparar o cancelamento da edio da linha (mtodo definido na propriedade OnCancelCommand do DataGrid);

Para a coluna ButtonColumn, as propriedades importantes so:

HeaderText Define o texto do cabealho;

Text Define o texto que aparecer em todas as linhas da coluna;

CommandName Define o comando a ser disparado;

Para a coluna HyperLinkColumn, as propriedades importantes so:

HeaderText Define o texto do cabealho;

Text Define o texto que aparecer em todas as linhas da coluna;

DataTextField Define o texto que aparecer em todas as linhas da coluna, baseado em um campo da fonte de dados;

DataTextFormatString Define o formato do texto que aparecer em todas as linhas da coluna, baseado na formatao de um campo da fonte de dados;

DataNavigateUrlField Define o campo da fonte de dados que servir para ser utilizado como parmetro de um link definido na propriedade DataNavigateUrlFormatString;

DataNavigateUrlFormatString Define o Link Dinmico que deve ser disparado pela linha, baseado em um campo da fonte de dados definido no campo DataNavigateUrlField;

Target Define elemento Target (HTML) que deve ser o foco do link;

NavigateUrl Define o Link Esttico que deve ser navegado ao clicar em qualquer linha;

OBS:

1) Para o texto a ser informado, possvel utilizar um truque: para que seja colocada uma imagem no lugar de texto, basta fornecer a tag IMG do HTML como texto, como se esse texto fosse a imagem, de forma que ela ser processada normalmente (veja esse recurso no exemplo abaixo).

2) O programador no precisa definir quem dispara o que no DataGrid, pois o ASP.NET faz isto automaticamente, bastando apenas fornecer o nome das rotinas de tratamento nas propriedades do DataGrid (mostrado em destaque no cdigo da pgina de exemplo abaixo).

Arquivo Simples.aspx (somente o tag DataGrid):

Arquivo Simples.aspx.cs (somente os novos mtodos):

protected void EditarGrid(Object sender, DataGridCommandEventArgs e)

{

Response.Write("Voc apertou o boto de Editar!");

//define a linha clicada em modo de edio

DG_Simples.EditItemIndex=e.Item.ItemIndex;

//remonta a tela

BindData();

}

protected void AtualizarGrid(Object sender, DataGridCommandEventArgs e)

{

Response.Write("Voc apertou o boto de Atualizar!");

//define nenhuma linha em modo de edio

DG_Simples.EditItemIndex=-1;

//aps a rotina e atualizao que estaria aqui remonta atela

BindData();

}

protected void DeletarGrid(Object sender, DataGridCommandEventArgs e)

{

//escreve na tela o Id do item a deletar

Response.Write("Voc apertou o boto de Deletar o Registro de au_id = '" + e.Item.Cells[0].Text + "'");

//aps a rotina e excluso que estaria aqui remontaria a tela

BindData();

}

protected void CancelarGrid(Object sender, DataGridCommandEventArgs e)

{

Response.Write("Voc apertou o boto de Cancelar!");

//define nenhuma linha em modo de edio

DG_Simples.EditItemIndex=-1;

//aps a rotina e cancelamento que estaria aqui remonta a tela

BindData();

}

Veja os Resultados:

Ao clicar em editar:

Ao clicar em deletar:

Ao clicar em Navegar (aqui, disparada uma segunda pgina Resultado.aspx, cujo cdigo est a seguir):

Exemplo do ItemTemplateColumn

Bem, at agora, pudemos ver o quanto o DataGrid poderoso. Entretanto, h um outro recurso do DataGrid que ir permitir que voc faa TUDO o que imaginar: esse recurso o ItemTemplate. Pelo conceito do ItemTemplate voc poder montar a coluna em cdigo HTML, da forma que quiser. Tomemos, por exemplo, as colunas de endereo, cidade, estado e CEP do exemplo anterior e vamos coloc-los na mesma coluna, numa formatao que a transforme em uma etiqueta de mala-direta:

Cdigo Simples.aspx (apenas para o tag ItemTemplate inserido no lugar das colunas dos campos citados acima):

Cdigo Simples.aspx.cs (NO se altera).

Veja o resultado:

Repare que o acesso aos campos se deu atravs da clusula:

DataBinder.Eval(Container.DataItem, "address")

Arquivo Resultado.aspx

Resultado

Arquivo Resultado.aspx.cs (SEM a parte automtica gerada pelo VS.NET)

using System;

using System.Collections;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Web;

using System.Web.SessionState;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Web.UI.HtmlControls;

namespace CoolDataGrid

{

public class Resultado : System.Web.UI.Page

{

protected System.Web.UI.WebControls.Button Button1;

private void Page_Load(object sender, System.EventArgs e)

{

// Put user code to initialize the page here

Response.Write("Voce Selecionou a Linha de ID = '" + Request.Params["AU_ID"] + "'");

}

}

}

Tudo at agora foi feito, tomando-se em considerao a montagem dos campos de forma esttica, ou seja, antes da pgina ser renderizada. Mas agora que vem a p de cal, pois os ItemTemplates podem ser alimentados de forma dinmica, com QUALQUER controle da web.

Vamos supor que no exemplo utilizado at agora fosse interessante para cada linha apresentar os ttulos de cada autor, com um DataGrid DENTRO do DataGrid principal. Este exemplo ser analisado no prximo item.

Usando o Conceito de Master/Detail DataGrid

Para que este conceito possa ser utilizado, tomemos uma coluna do tipo ItemTemplate e vamos aliment-la em tempo de execuo. Para isso, iremos apenas inserir uma nova coluna Item Template que no contenha nenhuma informao , e vamos trabalhar o evento OnBoundItem do DataGrid no cdigo que se encontra por trs da pgina (fazendo referncia ao mtodo nas propriedades do DataGrid):

Arquivo Simples.aspx (somente DataGrid):

Arquivo Simples.aspx.cs (somente o mtodo MontaLinha):

protected void MontaLinha(Object sender, DataGridItemEventArgs e)

{

//Verifica que tipo de linha est sendo criada

//pois queremos que rode somente em linhas Item e Alternating Item

// e no em Header e Footer

if(e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)

{

//cria um string auxiliar para montar a query

string strAux;

//Cria um novo objeto DataGrid para ser inserido

DataGrid TitulosGrid = new DataGrid();

//Formata o novo DataGrid.

TitulosGrid.BorderWidth = (Unit)1;

TitulosGrid.CellPadding = 4;

TitulosGrid.CellSpacing = 2;

TitulosGrid.GridLines = GridLines.Horizontal;

TitulosGrid.Font.Name = "Tahoma";

TitulosGrid.Font.Size = FontUnit.XSmall;

TitulosGrid.BorderColor = Color.FromName("Gray");

TitulosGrid.ItemStyle.BackColor = Color.FromName("HoneyDew");

TitulosGrid.ItemStyle.ForeColor = Color.FromName("DarkRed");

TitulosGrid.ShowHeader = true;

TitulosGrid.HeaderStyle.BackColor = Color.FromName("LightSteelBlue");

TitulosGrid.HeaderStyle.ForeColor = Color.FromName("DarkRed");

TitulosGrid.HeaderStyle.Font.Bold = true;

//Marca para no gerar automaticamente as colunas

TitulosGrid.AutoGenerateColumns = false;

//Adiciona as colunas da grid//

//Id do titulo//

BoundColumn bc = new BoundColumn();

//Configura os valores desta BoundColumn

bc.HeaderText = "ID do Ttulo";

bc.DataField = "Id";

bc.ItemStyle.Wrap = false;

bc.Visible=false;

//Adiciona esta coluna a DataGrid.

TitulosGrid.Columns.Add(bc);

//Ttulo//

bc = new BoundColumn();

bc.HeaderText = "Ttulo";

bc.DataField = "Titulo";

bc.ItemStyle.Wrap = false;

TitulosGrid.Columns.Add(bc);

//Tipo do Ttulo//

bc = new BoundColumn();

bc.HeaderText = "Tipo do Ttulo";

bc.DataField = "Tipo";

bc.ItemStyle.Wrap = false;

TitulosGrid.Columns.Add(bc);

//Valor Recebido em formato Currency//

bc = new BoundColumn();

bc.HeaderText = "$ Recebido";

bc.DataField = "Earned";

bc.DataFormatString="{0:c}";

bc.ItemStyle.Wrap = false;

TitulosGrid.Columns.Add(bc);

//Fim das Colunas//

//Cria os novos objetos de Banco de dados para criao do DataReader para alimentar

// esta DataGrid

//objeto connection PODE SER O MESMO QUE O ANTERIOR

//objeto command NO PODE SER O MESMO QUE O ANTERIOR (LEMBRAR QUE A CONEXAO ESTA ABERTA

//cria o comando de acordo com o ID da linha

//verifica antes se a conexo est aberta, seno abre

if (sqlConnection1.State == ConnectionState.Closed)

{

sqlConnection1.Open();

}

strAux = strSQL2 + " WHERE authors.au_id = '" + e.Item.Cells[0].Text + "'";

System.Data.SqlClient.SqlCommand sqlComd2 = new System.Data.SqlClient.SqlCommand(strAux,sqlConnection1);

//cria um objeto DataReader para executar o Reader

System.Data.SqlClient.SqlDataReader sqlDR;

//executa o comando para o reader

sqlDR = sqlComd2.ExecuteReader();

//preenche o DataGrid com o Reader

TitulosGrid.DataSource = sqlDR;

TitulosGrid.DataBind();

//Fecha a conexo - LEMBRAR DE FECHAR SEMPRE QUE UTILIZAR DATAREADER

sqlConnection1.Close();

//Adiciona este DataGrid ao DataGrid Original na coluna Template vazia.

//lembrar que o ndice comea de 0

e.Item.Cells[4].Controls.Add(TitulosGrid);

}

}

Veja o resultado:

Agora vamos aos comentrios:

1) Nada impede que seja inserido mais de um controle na mesma coluna TemplateColumn;

2) Nada impede que em uma coluna de qualquer tipo (no somente a TemplateColumn), possa receber um novo controle (veja esta opo por exemplo com a alterao do nmero da coluna na listagem acima, tomando apenas o cuidado de no colocar um nmero fora do escopo, que de zero at o nmero mximo de colunas menos um). Alm disto, a insero de controles, pode ser feita com qualquer controle (no necessariamente um DataGrid como utilizamos) e pode tambm ser mais de um controle (um DataGrid, e um HyperLink Button por exemplo).

3) Os exemplos acima foram meramente ilustrativos, e no receberam nenhum tratamento de erros. Este no o melhor procedimento. Uma aplicao profissional dever sempre passar por um bom tratamento de erros.

4) Na listagem acima, foi feita a verificao do estado da conexo, pois reparem que ela foi fechada antes que a rotina DataBind tivesse sido chamada. Mas, se a rotina fosse chamada aps a conexo a listagem estaria aberta e no haveria necessidade de abri-la novamente. Mantive este exemplo apenas para ilustrar que toda ateno deve ser dedicada s conexes com o Banco de Dados que so verdadeiros gargalos de memria em aplicaes web;

5) Nada impediria, tambm, que se criasse um novo TemplateColumn dentro do novo DataGrid, ou mesmo que se criasse uma coluna de outro tipo como Button, HyperlInk, etc.

O ltimo tpico do objeto DataGrid, a seguir, tratar sobre a criao de uma paginao e ordenao customizadas.

Usando a Ordenao e a Paginao Customizadas no DataGrid

J mencionamos os lados positivos da paginao e ordenao do DataGrid. De fato, a paginao e ordenao so recursos muito bons, desde que o programador no se encontre em uma situao extrema, na qual ele tenha muitos registros em uma busca ou em uma tabela, ou quando as queries so bastante complexas. Nos casos extremos (muito comuns, na verdade) a paginao e ordenao no atendem s expectativas, pois esses dois recursos sempre iro fazer a busca de TODOS os dados da fonte de dados, fazendo apenas a filtragem automtica daquilo que for mostrado.

Numa aplicao profissional recomenda-se utilizar o conceito de paginao customizada, previsto pelo prprio DataGrid, atravs da propriedade AllowCustomPaging, que, como padro, False.

Primeiramente, vamos definir esta propriedade como True. Em seguida, vamos criar os elementos adicionais da pgina que iro tratar da paginao que, neste caso, so os botes adicionais.

O conceito que se econtra por trs da paginao o de uma Stored Procedure Especial que ir fazer todo o trabalho de ordenao e paginao no SQL, retornando apenas os registros desejados de forma a maximizar a performance da aplicao. Este tutorial no tem o propsito de explicar T-SQL, portanto, no exemplo que se segue, ser apenas apresentado o cdigo da Stored Procedure. (Observe que o script faz a verificao da existncia da Stored Procedure antes de cri-la. Entretanto, essa parte no obrigatria.)

SET QUOTED_IDENTIFIER ON

GO

SET ANSI_NULLS ON

GO

if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[spPaginacao]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)

drop procedure [dbo].[spPaginacao]

GO

CREATE PROCEDURE spPaginacao

@SQL VARCHAR(4000),

@PAGE INT,

@PAGESIZE INT,

@ORDER VARCHAR(255) = ' ',

@TIPOORDER VARCHAR(4) = 'ASC',

@ROWS_TOTAL INT OUT,

@INT_ERRO INT OUT

WITH RECOMPILE /* Esta clusula para garantir que seja o melhor desempenho */

AS

BEGIN

DECLARE @START_ROW INT

/* LINHA DE INCIO */

DECLARE @ROWS_REQUIRED INT /* LINHAS REQUERIDAS */

DECLARE @TOTAL INT

/* TOTAL DE LINHAS */

DECLARE @PARAMETERS NVARCHAR(255) /* AUXILIAR PARA GUARDAR PARMETRO */

DECLARE @EXECSQL NVARCHAR(4000) /* AUXILIAR PARA GUARDAR COMANDO SQL */

DECLARE @ORDEM1 NVARCHAR(4) /* AUXILIAR PARA GUARDAR A ORDENAAO PRIMEIRA E TERCEIRA */

DECLARE @ORDEM2 NVARCHAR(4) /* AUXILIAR PARA GUARDAR A ORDENAAO SEGUNDA */

DECLARE @TEMP_NUMREG INT /* AUXILIAR PARA GUARDAR A NMERO DE REGISTROS TEMPORRIOS */

DECLARE @TEMP_ULTPAG INT

/* AUXILIAR PARA GUARDAR A LTIMA PGINA POSSVEL */

DECLARE @TEMP_REGULTPAG INT /* AUXILIAR PARA GUARDAR O NMERO DE REGISTROS DA LTIMA PGINA POSSVEL */

/* **** CALCULA A LINHA DE INCIO E O NMERO DE LINHAS NECESSRIAS **** */

SET @START_ROW = (@PAGESIZE * (@PAGE - 1)) + 1

SET @ROWS_REQUIRED = @PAGESIZE

/* CALCULA O TOTAL DE REGISTROS **** */

SET @EXECSQL = N'SELECT @TOT=COUNT(*) FROM (' + @SQL + ') AS AUX'

SET @PARAMETERS =N'@TOT INT OUTPUT'

EXEC SP_EXECUTESQL @EXECSQL,@PARAMETERS,@TOT=@TOTAL OUTPUT

/* VERIFICA SE O NMERO DA PGINA VIVEL **** */

IF (@TOTAL @TOTAL)

BEGIN /* A PGINA MAIOR QUE O TOTAL */

SET @ROWS_TOTAL = 0

SET @INT_ERRO = -1

END

ELSE /* PODE RODAR O PROCEDIMENTO */

BEGIN

SET @ROWS_TOTAL=@TOTAL

SET @TEMP_ULTPAG = (FLOOR(@TOTAL/@PAGESIZE))+1

SET @TEMP_REGULTPAG = @TOTAL-(@PAGESIZE*(@TEMP_ULTPAG-1))

IF @PAGE = 0

BEGIN /* RETORNA TODA A TABELA */

SET @EXECSQL = N'SELECT * FROM (' + @SQL + ') AS AUX'

IF @ORDER ' '

BEGIN

SET @EXECSQL = @EXECSQL + ' ORDER BY ' + @ORDER + ' ' + @TIPOORDER

END

END

ELSE /* RETORNA SOMENTE A PGINA DESEJADA */

BEGIN

IF @TIPOORDER = 'ASC'

BEGIN

SET @ORDEM1 = 'ASC'

SET @ORDEM2 = 'DESC'

END

ELSE

BEGIN

SET @ORDEM1 = 'DESC'

SET @ORDEM2 = 'ASC'

END

SET @TEMP_NUMREG = @PAGESIZE * @PAGE

SET @EXECSQL = N'SELECT TOP ' + cast(@TEMP_NUMREG as varchar(255)) + ' * INTO #T1 FROM (' + @SQL + ') AS AUX ORDER BY ' + @ORDER + ' ' + @ORDEM1

IF ((@PAGE > 1) AND (@PAGE < @TEMP_ULTPAG))

BEGIN

SET @TEMP_NUMREG = @PAGESIZE

SET @EXECSQL = @EXECSQL + ' SELECT TOP ' + cast(@TEMP_NUMREG as varchar(255)) + ' * INTO #T2 FROM #T1 ORDER BY ' + @ORDER + ' ' + @ORDEM2

SET @EXECSQL = @EXECSQL + ' SELECT * FROM #T2 ORDER BY ' + @ORDER + ' ' + @ORDEM1

END

ELSE

BEGIN

IF @PAGE = @TEMP_ULTPAG

BEGIN

SET @TEMP_NUMREG = @TEMP_REGULTPAG

SET @EXECSQL = @EXECSQL + ' SELECT TOP ' + cast(@TEMP_NUMREG as varchar(255)) + ' * INTO #T2 FROM #T1 ORDER BY ' + @ORDER + ' ' + @ORDEM2

SET @EXECSQL = @EXECSQL + ' SELECT * FROM #T2 ORDER BY ' + @ORDER + ' ' + @ORDEM1

END

ELSE

BEGIN

SET @EXECSQL = @EXECSQL + ' SELECT * FROM #T1 ORDER BY ' + @ORDER + ' ' + @ORDEM1

END

END

END

EXEC SP_EXECUTESQL @EXECSQL

IF @@ERROR = 0

BEGIN

SET @INT_ERRO = 0

END

ELSE

BEGIN

SET @INT_ERRO = -2

END

END

END

END

GO

SET QUOTED_IDENTIFIER OFF

GO

SET ANSI_NULLS ON

GO

Esta Stored Procedure deve estar na tabela do sistema que se deseja utilizar. No nosso caso, adicionamos a mesma na tabela Pubs do SQL Server. O mais importante so os parmetros que ela utiliza:

@SQL VARCHAR(4000)

Instruo SQL que ser utilizada na query;

@PAGE INT

Nmero da Pgina (devendo estar entre 1 e o nmero total de pginas, caso contrrio retornar erro;

@PAGESIZE INT

Nmero de Pginas;

@ORDER VARCHAR(255) = ' ' Campo utilizado na ordenao;

@TIPOORDER VARCHAR(4) = 'ASC' Tipo de Ordenao (ASC ou DESC);

@ROWS_TOTAL INT OUT

Sada com o Total de Linhas;

@INT_ERRO INT OUT

Sada com Retorno de Sucesso (0) ou Erro ( 0);

Para avaliarmos o potencial deste procedimento, basta implementar a nova pgina MasterDetail.aspx que utiliza esta Stored Procedure e os novos botes para a navegao customizada. Apenas a ttulo de informao, utilizei tambm dois controles Label para identificar as pginas. Veja o cdigo da pgina a seguir:

MasterDetail.aspx:

MasterDetail

.table { FONT: x-small Tahoma; COLOR: navy }

.tableItem { FONT: x-small Tahoma; COLOR: navy; BACKGROUND-COLOR: floralwhite }

.tableHeader { FONT: bold x-small Tahoma; COLOR: black; BACKGROUND-COLOR: darkseagreen }

.alternatingItem { FONT: x-small Tahoma; COLOR: navy; BACKGROUND-COLOR: silver }

Pgina

de

MasterDetail.aspx.cs (SEM a parte gerada automaticamente pelo VS.NET):

using System;

using System.Collections;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Web;

using System.Web.SessionState;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Web.UI.HtmlControls;

using System.Data.SqlClient;

namespace CoolDataGrid

{

public class MasterDetail : System.Web.UI.Page

{

protected System.Web.UI.WebControls.Label Lbl_Pagina_Final;

protected System.Web.UI.WebControls.Label Lbl_Registros;

protected System.Web.UI.WebControls.Label Lbl_Pagina_Atual;

protected System.Web.UI.WebControls.Label Label3;

protected System.Web.UI.WebControls.Label Label1;

protected System.Web.UI.WebControls.DataGrid DG_MasterDetail;

protected System.Web.UI.WebControls.ImageButton Cmd_First;

protected System.Web.UI.WebControls.ImageButton Cmd_Previous;

protected System.Web.UI.WebControls.ImageButton Cmd_Next;

protected System.Web.UI.WebControls.ImageButton Cmd_Last;

protected System.Web.UI.WebControls.Label Lbl_Sql;

protected System.Web.UI.WebControls.Label Lbl_Order;

//tipos personalizados

protected SqlConnection sqlConn;

protected SqlCommand sqlCmd;

protected SqlDataReader sqlDR;

protected int Int_Cur_Page;

protected int Int_Tot_Page;

protected string strSQL = "SELECT au_id,au_fname,au_lname,city,address,state,zip FROM authors";

protected string strSQL2 = "SELECT titles.title_id AS Id,titles.title AS Titulo,titles.type AS Tipo,((price*ytd_sales*royalty)/100) AS Earned FROM titles INNER JOIN titleauthor ON titles.title_id = titleauthor.title_id INNER JOIN authors ON titleauthor.au_id = authors.au_id";

private void Page_Load(object sender, System.EventArgs e)

{

// Roda se no for auto submit

if (! IsPostBack)

{

Int_Cur_Page=1;

//coloca os valores nas Labels para armazenar estado

Lbl_Pagina_Atual.Text=Int_Cur_Page.ToString();

Lbl_Order.Text="au_fname";

Lbl_Sql.Text=strSQL;

//monta a Grid

BindData();

}

}

private void BindData()

{

string Str_Saida="";

int int_aux;

decimal dec_aux;

//estabelece a conexo

sqlConn = new SqlConnection("Data Source=localhost;User ID=SA;Password=;Initial Catalog=pubs");

sqlCmd = new SqlCommand();

sqlCmd.Connection=sqlConn;

Lbl_Registros.Text="";

//desta vez vamos colocar tratamento de erros

try

{

//define a stored procedure e seus parametros

sqlCmd.CommandText="spPaginacao";

sqlCmd.CommandType=CommandType.StoredProcedure;

//limpa apilha de parmetros apenas para conforto (no necessrio)

sqlCmd.Parameters.Clear();

sqlCmd.Parameters.Add(new SqlParameter("@SQL",SqlDbType.VarChar,4000));

sqlCmd.Parameters["@SQL"].Value=Lbl_Sql.Text;

sqlCmd.Parameters.Add(new SqlParameter("@PAGE",SqlDbType.Int));

sqlCmd.Parameters["@PAGE"].Value=Int_Cur_Page;

sqlCmd.Parameters.Add(new SqlParameter("@PAGESIZE",SqlDbType.Int));

sqlCmd.Parameters["@PAGESIZE"].Value=DG_MasterDetail.PageSize;

sqlCmd.Parameters.Add(new SqlParameter("@ORDER",SqlDbType.VarChar,255));

sqlCmd.Parameters["@ORDER"].Value=Lbl_Order.Text;

sqlCmd.Parameters.Add(new SqlParameter("@TIPOORDER",SqlDbType.VarChar,4));

sqlCmd.Parameters["@TIPOORDER"].Value="ASC";

sqlCmd.Parameters.Add(new SqlParameter("@ROWS_TOTAL",SqlDbType.Int));

sqlCmd.Parameters["@ROWS_TOTAL"].Direction=ParameterDirection.Output;

sqlCmd.Parameters.Add(new SqlParameter("@INT_ERRO",SqlDbType.Int));

sqlCmd.Parameters["@INT_ERRO"].Direction=ParameterDirection.Output;

//abre a conexo com o banco de dados

sqlConn.Open();

//executa o reader

sqlDR=sqlCmd.ExecuteReader();

//atribui o reader a DataGrid

DG_MasterDetail.DataSource=sqlDR;

DG_MasterDetail.DataBind();

//fecha a conexo

sqlConn.Close();

//verifica se ocorreu algum erro com a query

if (((int)sqlCmd.Parameters["@INT_ERRO"].Value)==0)

{

//calcula o nmero total de pginas atravs do nmero de registros totais

int_aux = ((int)sqlCmd.Parameters["@ROWS_TOTAL"].Value);

dec_aux=(Decimal.Parse(int_aux.ToString()))/DG_MasterDetail.PageSize;

Int_Tot_Page=Int32.Parse(System.Math.Ceiling(Double.Parse(dec_aux.ToString())).ToString());

//preenche os Labels para armazenar o estado

Lbl_Pagina_Atual.Text=Int_Cur_Page.ToString();

Lbl_Pagina_Final.Text=Int_Tot_Page.ToString();

Lbl_Registros.Text = "Total de Registros: " + int_aux.ToString();

//verifica como apresentar os botes de acordo com a pgina que se encontra

if (Int_Tot_Page==1)

{

Cmd_First.Visible=false;

Cmd_Next.Visible=false;

Cmd_Previous.Visible=false;

Cmd_Last.Visible=false;

}

else

{

if (Int_Cur_Page==1)

{

Cmd_First.Visible=false;

Cmd_Next.Visible=true;

Cmd_Previous.Visible=false;

Cmd_Last.Visible=true;

}

else

{

if (Int_Cur_Page==Int_Tot_Page)

{

Cmd_First.Visible=true;

Cmd_Next.Visible=false;

Cmd_Previous.Visible=true;

Cmd_Last.Visible=false;

}

else

{

Cmd_First.Visible=true;

Cmd_Next.Visible=true;

Cmd_Previous.Visible=true;

Cmd_Last.Visible=true;

}

}

}

}

else

{

Response.Write("Ocorreu um Erro com a procura!");

}

}

catch (SqlException e)

{

//trata do erro de banco de dados

for (int i=0; i