Desenvolvimento - ASP. NET

ASP.NET: Classe para tratamento de DataGrid

Toda vez que trabalhamos com dados em componentes do tipo DataGrid estamos sujeitos à algumas dificuldades. Um exemplo seria quando tentamos remover o último item de uma página do DataGrid e, após recarregar os dados, a página atual do DataGrid passa a ser maior do que o número de páginas existentes, gerando uma exceção.

por Artur Caliendo Prado



Introdução

Toda vez que trabalhamos com dados em componentes do tipo DataGridestamos sujeitos à algumasdificuldades. Um exemploseria quando tentamos removero últimoitem de uma página do DataGrid ( imagine uma tabela com 3 itens e 2 itens por página, e excluímos o terceiro item)e, após recarregar os dados,a página atual do DataGridpassa a ser maior do que o número de páginas existentes, gerando uma exceção. Através de uma classe é possível centralizar todas as funçõesa serem utilizadas e evitar a repetição de código para cada DataGrid criado, agilizando a criação de páginas e minimizando os erros de desenvolvimento.

Identificando o problema

O primeiro passo para corrigir os repetitivos erros que ocorremcom os DataGrids é identificar em quais momentos os erros ocorrem.

1. Quando criamos um novo registro;

2. Ao tentar criar um novo registro, a página do DataGrid pode estar cheia, fazendo com que o novo registro apareça na página seguinte. Porém, se a inserção falhar e a execução não for interrompida ou devidamente tratada, o DataGrid, após ser recarregado, tentará manter-se na página nova, mas esta não existirá, uma vez que o dado não foi inserido;

3. Ao excluir o último registro de uma pagina e recarregar os dados do DataGrid.

A princípio estes são os momentos principais onde nosso programa é interrompidocomalguma excessão. Outros erros podem ocorrer mas, criando-se um classe para tratar os DataGrids, qualquer alteração desejada é feita em apenas um lugar, tornando o processo muito mais inteligente.

Implementação

Neste artigo, utilizaremos a linguagem C# .NET.

Crie uma bibilioteca de classes. Para fazer isso, clique com o botão direito do mouse sobre a soluçãoe escolha "Add", e, em seguida, "New Project". Procure nos templates o item "Class Library". Dê um nome para a bibliotecae pressiona "OK". Após criar o projeto, clique com o botão direito do mouse sobre o projeto e escolha "Add", e "Add New Item". Adicione uma classe ("Class"), e dê a ela o nome de "ObjGrid.cs". Pronto, já criamos a classe que irá fazer os tratamentos necessários nos DataGrids.

Vamos começar a solucionar os problemas. Todos os tipos de alterações feitas no DataGridexigem que ele seja recarregado no final do método. Então, podemos criar um método para que ele seja recarregado com segurança, de modo que, se ele estiver em uma página que não existe, o DataGrid volte para uma página válida.

Para utilizar DataSet e DataGrid na classe ObjGrid.cs, adicione:
				
using System.Data;
using System.Web.UI.WebControls;
Crie o seguinte método:

public static void BindGrid(DataSet ds, DataGrid dg)
{
	//Guarda a página em que o DataGrid está antes de ser recarregado.
	int pos = dg.CurrentPageIndex;
	//Muda a página atual para a página zero, evitando erros durante o DataBind()
	dg.CurrentPageIndex = 0;
	//Atualiza o DataGrid
	dg.DataSource = ds;
	dg.DataBind();
	//Caso a página em que o DataGrid estava antes de ser recarregado não existir,
	//deve-se buscar a última página válida.
	while (pos > dg.PageCount-1 && pos > 0) pos--;
	//Coloca o Grid em uma página válida.
	dg.CurrentPageIndex = pos;
	//Atualiza o DataGrid na página.
	dg.DataBind();
}

É importante que o método seja estático, para que não seja necessário instanciar a classe toda vez que um DataGrid sofrer alguma alteração. Porém, nem sempre usamos um DataSet para preencher DataGrids. Podemos usar outras fontes, como DataTable ou DataView. Para que a classe fique completa, crie uma sobrecarga deste método para os tipos que você precisar em seu projeto.

Quando mudamos um DataGrid de páginageralmente esperamosque ele saia do "modo edição", e não possua mais nenhum item selecionado, uma vez que estaremos indo para uma página nova. Este, assim como outros métodos criados neste artigo, são opcionais. Você também deve adaptá-lo às suas necessidades, se precisar que os DataGrids possuam umcomportamento específico.

Para resolver o problema de mudança de página, podemos criar o seguinte método:

public static void TrocaPagina(DataGrid dg, int newPageIndex)
{
	//Garante que nenhum item permanecerá selecionado.
	dg.SelectedIndex = -1;
	//Tira o DataGrid do modo edição.
	dg.EditItemIndex = -1;
	//Atualiza a página do DataGrid
	dg.CurrentPageIndex = newPageIndex;
}
Se desejar, adicione mais um parâmetro ao método (o DataSet, ou qualquer fonte de dados para preenchimento do DataGrid) e chame o método BindGrid antes de terminar o método TrocaPagina, diminuindoa necessidade de criar código repetitivo em suas páginas. Então, o métodoficariaassim:
public static void TrocaPagina(DataGrid dg,int newPageIndex, DataSet ds)
{
	//Garante que nenhum item permanecerá selecionado.
	dg.SelectedIndex = -1;
	//Tira o DataGrid do modo edição.
	dg.EditItemIndex = -1;
	//Atualiza a página do DataGrid
	dg.CurrentPageIndex = newPageIndex;
	//Recarrega os dados.
	BindGrid(ds, dg);
}
Adicione os dois métodos a seguir para aumentar a quantidade de opções:

public static bool ModoEdicao(DataGrid dg,DataSet ds, int itemIndex)
{
	bool    

	 retorno = false;
	if (ObjGrid.PodeEditar(dg))
	{
		retorno = true;
		//Seleciona o item.
		dg.SelectedIndex = itemIndex;
		//Coloca o DataGrid em modo edição.
		dg.EditItemIndex = itemIndex;
		//Recarrega os dados.
		BindGrid(ds, dg);
	}
	else
	{
		retorno = false;
	}
	return retorno;
}
E o método para verificar se um DataGrid já está sendo editado:
public static bool PodeEditar(DataGrid dg)
{
	return (dg.EditItemIndex == -1);
}

No método "ModoEdicao" pode ser indesejável chamar o "BindGrid" dentro da classe. Como dito anteriormente, altere a classe de acordo com as suas necessidades. Para finalizar, temos o problema da inserção de novos registros. Aplicações que utilizam muitos DataGrids e fazem as alterações e inserções diretamente no componente tendem a repetir o mesmo código de inserção para cada Grid. O ideal é mantermos o método nesta classe, a chamá-lo quando necessário.

Lembre-se que é necessário que o DataSet passado como parâmetro esteja devidamente preenchido. Utilize outras classes de dados, como o DataTable, se achar necessário.

public static void NovoRegistro(DataSet ds, DataGrid dg)
{
	int ValorIndex;
	//Cria uma nova linha para ser inserida no DataSet
	DataRow novoRegistro = ds.Tables[0].NewRow();
	//Inserindo a nova linha no final do DataSet.
	ds.Tables[0].Rows.InsertAt(novoRegistro,Convert.ToInt16 (ds.Tables[0].Rows.Count.ToString()));
	//Obtém a posição do novo item, para usar como EditItemIndex.
	ValorIndex=(ds.Tables[0].Rows.Count %dg.PageSize)-1 ;  
	//Se o DataSet não possuía linhas, devemos prepará-lo para seu primeiro registro.
	//Esta condição também serve para perceber se a página atual já está cheia de registros,.
	//Preparando o registro para ser colocado na próxima página.
	if (ValorIndex == -1)
	{
		ValorIndex=Convert.ToInt32 (dg.PageSize)-1;
	}

	//Se o registro for o primeiro de uma nova página, temos que resolver um problema.
	//A propriedade PageCount do DataGrid não está contando com a linha que acabamos de inserir, uma 
	//vez que este dado ainda não faz parte do DataGrid.
	if ((ds.Tables[0].Rows.Count >  1 )&&(ValorIndex==0))
	{
		dg.CurrentPageIndex = dg.PageCount;
	}
	else
	{
		dg.CurrentPageIndex = dg.PageCount-1;
	}
	//Finalmente, colocamos o DataGrid no modo de edição e carregamos os dados.
	dg.EditItemIndex = ValorIndex;
	dg.SelectedIndex = ValorIndex;

	ObjGrid.BindGrid(ds,dg);
}

Mas como usar esta classe? Se você entendeu como ela é feita, já sabe que é muito simples utilizar seus recursos. Abaixo segue um exemplo de utilização da classe, para cada tipo de modificação feita no DataGrid.

Existem duas possibilidades:

1. O DataSet dsCep é armazenado em uma viewState, e pode ser usado em qualquer método.

Isto não é uma boa prática se o DataSet possuir grande quatidade de dados. Então usaremos a opção 2.


2. O método getDataSet() faz uma consulta na base de dados e retorna os dados em um DataSet.

Neste caso, a página fará várias conexões com a base de dados, mas não guardará os dados em ViewStates.

			
protected void dgCep_PageIndexChanged(object source, System.Web.UI.WebControls.DataGridPageChangedEventArgs e)
{
	ObjGrid.TrocaPagina(dgCep, e.NewPageIndex, getDataSet());
}

protected void dgCep_Edit(Object source, DataGridCommandEventArgs e)
{
	if (!ObjGrid.ModoEdicao(dgCep, getDataSet(), e.Item.ItemIndex))
	{
		lblAviso.Text = "Termine de editar o DataGrid antes de inciar o modo edição.";
	}
}
           
protected void BindGridCep()
{
	ObjGrid.BindGrid(dgCep, getDataSet());
}

protected void dgCep_Cancel(Object sender, DataGridCommandEventArgs e)
{
	dgCep.EditItemIndex = -1;
	dgCep.SelectedIndex = -1;
	BindGridCep();
}
O evento mais complexo, de inserir um novo registro, ficou muito simples. Observe:
private void imgIncluirCep_Click(object sender, System.Web.UI.ImageClickEventArgs e)
{
	if (ObjGrid.PodeEditar(dgCep))
	{
		ObjGrid.NovoRegistro(getDataSet(), dgCep);
	}
}

Ao final dos métodos de Update e de Delete você terá que recarregar o DataGrid. Para isso, chame o método BindGridCep(). Com isso, com certeza você não terá mais problemas de páginas que não existem!


Se desejar, pegue o código pronto aqui .

Artur Caliendo Prado

Artur Caliendo Prado - Membro da célula acadêmica Fellowship .net. Trabalha com .NET desde junho de 2003. Participou do Imagine Cup 2004, e sua equipe conseguiu o terceiro lugar na etapa brasileira. Participou do projeto Assignment Manager, da Microsoft, pela Unesp de Bauru, como coordenador da equipe de desenvolvimento. Atualmente trabalha com desenvolvimento de software em ASP.NET, além de realizar palestras sobre a plataforma .NET.