Formatação Avançada de DataGrid com ItemDataBound
Veja neste artigo, como implementar formatações no DataGrid, simulando agrupamento de valores.
Formatação Avançada de DataGrid com ItemDataBound
Estava querendo produzir DataGrids com as mesmas funcionalidades de relatórios impressos e a coisa toda se parecia com alguns sistemas de gerenciamento de informações muito caros que foram substituídos com o .NET. O produto final deveria focar a atenção dos usuários nos dados desejados, sem as complicações de campos extras e outros detalhes. Este artigo se propõe a introduzir o uso de alguns truques simples para incrementar a aparência dos DataGrids.
Veremos então como fazer para:
· Criar agrupamentos de colunas
· Realçar subtotais e totais gerais
· Realçar células individuais com base em valores de dados
Dados SQL e Banco de dados
Foram usados o Northwind e o SQL Server DB para produzir os dados para este artigo, com um subtotal para cada categoria de produto e um total geral no final. O código funcionará para qualquer fonte de dados. As stored procedures SQL foram também incluídas para aqueles que estejam interessados em recriar exatamente o que é mostrado aqui.
Quase toda a lógica de negócio foi colocada no lado do banco de dados, usando o DataGrid apenas para fins de exibição, portanto, toda a ordenação e os totais são feitos aqui.
CREATE PROCEDURE usp_sales_by_cate AS
create table #temp ( Sorty int, CategoryName varchar(50),
ProductName varchar(50), ProductSales real)
-- Get Base Sales
INSERT INTO #temp
SELECT 0, dbo.Categories.CategoryName, dbo.Products.ProductName,
SUM(dbo.[Order Details Extended].ExtendedPrice)
AS ProductSales
FROM dbo.Categories INNER JOIN
dbo.Products INNER JOIN
dbo.Orders INNER JOIN
dbo.[Order Details Extended] ON dbo.Orders.OrderID =
dbo.[Order Details Extended].OrderID ON
dbo.Products.ProductID =
dbo.[Order Details Extended].ProductID ON dbo.Categories.CategoryID =
dbo.Products.CategoryID
WHERE (dbo.Orders.OrderDate BETWEEN '19970101' e '19971231')
GROUP BY dbo.Categories.CategoryName, dbo.Products.ProductName
ORDER BY dbo.Categories.CategoryName
-- Build SubTotal
INSERT INTO #temp
SELECT 1 , CategoryName, 'SubTotal', sum( ProductSales)
from #temp
group by CategoryName
-- Build Grand Total
INSERT INTO #temp
SELECT 2 , 'XXXXX', 'Grand Total', sum( ProductSales)
from #temp
Where sorty = 0
-- Display Values
SELECT CategoryName, ProductName, ProductSales from #temp
order by CategoryName, Sorty
Criando Agrupamentos
Não queremos que as categorias sejam exibidas sempre na primeira coluna, porém apenas quando mudarem, o que dará um aspecto limpo e agradável ao DataGrid, permitindo aos usuários achar os itens rápida e facilmente.
Primeiro, criamos uma variável pública que funcionará para a página inteira e, o mais importantemente, lembrará algo a cada vez que o <ITEMDATABOUND> rodar para cada linha do DataGrid. O Page Load, será também pré-configurado (ocorreram algumas situações estranhas em que isto não aconteceu).
public class WebForm1 : System.Web.UI.Page
{
public string LastColumn;
..
..
private void Page_Load(object sender, System.EventArgs e)
{
// Configurar LastColumn para branco
if (!IsPostBack) LastColumn = "";
A seguir, usamos a variável <LASTCOLUMN> para localizar as alterações nos dados que irão para o DataGrid. Se o valor da célula de cell[0] não for alterado, o texto da mesma será apagado e a borda será removida:
e.Item.Cells[0].Style.Add("BORDER", "none").
Para ignorar o cabeçalho (header) do DataGrid:
if( ( e.Item.ItemType.ToString()!= "Header"))
{.....
Isto também pode ser utilizado para os itens, itens alternativos e rodapés (footers) em um DataGrid, para especializar o código.
A seguir, o código completo para agrupar a primeira coluna do DataGrid:
private void DataGrid1_ItemDataBound(object sender,
System.Web.UI.WebControls.DataGridItemEventArgs e)
{
//Obter o texto da coluna 0 atual
string CurrentColumn = e.Item.Cells[0].Text;
// Pular Headers
if( ( e.Item.ItemType.ToString()!= "Header"))
{
// Houve alguma alteração
if (CurrentColumn == LastColumn)
{
// Sem alteração na Coluna 0
//limpar e remover a borda
e.Item.Cells[0].Text = "";
e.Item.Cells[0].Style.Add("BORDER", "none");
}
else
{
// esta eh a primeira da serie
// atribuir LastColumn para a coluna atual
LastColumn = CurrentColumn;
// Adicionar uma cor de fundo para Cell[0]
e.Item.Cells[0].BackColor =
System.Drawing.Color.WhiteSmoke;
}
}
Realçando Subtotais e Totais Gerais
Isto é bastante simples, caso o texto da célula for "Sub Total" / "Grand Total", então configuramos a fonte, o tipo, as cores, etc.
// Verificar se eh um SubTotal
string MyCol2 = e.Item.Cells[1].Text;
if (MyCol2 == "SubTotal")
{
e.Item.Font.Bold = true;
e.Item.BackColor = Color.DimGray;
e.Item.ForeColor = Color.White;
// limpar Column 0
e.Item.Cells[0].Text = "";
e.Item.Cells[0].Style.Add("BORDER", "none");
e.Item.Cells[0].BackColor = Color.Transparent;
}
if (MyCol2 == "Grand Total")
{
e.Item.Font.Bold = true;
e.Item.BackColor = Color.Red;
e.Item.ForeColor = Color.White;
e.Item.Cells[0].Style.Add("BORDER", "none");
e.Item.Cells[0].BackColor = Color.Transparent;
}
Realçando Células Individuais
Este recurso é amplamente utilizado para exibir valores negativos em vermelho (do modo como se faz em contabilidade). Descobrimos que a conversão de string para número, pode produzir alguns erros estranhos, por isso, geralmente envelopamos as conversões em um try/catch para ignorar qualquer erro que possa surgir.
// Destacar itens caso as vendas estejam abaixo de 5000
string MyStr = e.Item.Cells[2].Text;
try
{
double MyValue = double.Parse(MyStr);
if (MyValue < 5000 )
{
e.Item.Cells[2].ForeColor = Color.Red;
e.Item.Cells[2].Font.Bold = true;
}
}
catch(Exception)
{
// numero invalido
}
Artigos relacionados
-
Artigo
-
Artigo
-
Artigo
-
Artigo
-
Artigo