Uso de TemplateFields no controle DetailsView (C#)
por Scott Mitchell
Os mesmos recursos TemplateFields disponíveis com o GridView também estão disponíveis com o controle DetailsView. Neste tutorial, exibiremos um produto por vez usando um DetailsView contendo TemplateFields.
Introdução
O TemplateField oferece um grau mais alto de flexibilidade na renderização de dados do que o BoundField, CheckBoxField, HyperLinkField e outros controles de campo de dados. No tutorial anterior, vimos como usar o TemplateField em um GridView para:
- Exiba vários valores de campo de dados em uma coluna. Especificamente, os
FirstName
campos eLastName
foram combinados em uma coluna GridView. - Use um controle Web alternativo para expressar um valor de campo de dados. Vimos como mostrar o
HiredDate
valor usando um controle Calendar. - Mostrar informações de status com base nos dados subjacentes. Embora a
Employees
tabela não contenha uma coluna que retorne o número de dias que um funcionário esteve no trabalho, pudemos exibir essas informações no exemplo GridView no tutorial anterior com o uso de um TemplateField e um método de formatação.
Os mesmos recursos TemplateFields disponíveis com o GridView também estão disponíveis com o controle DetailsView. Neste tutorial, exibiremos um produto por vez usando um DetailsView que contém dois TemplateFields. O primeiro TemplateField combinará os UnitPrice
campos , UnitsInStock
e UnitsOnOrder
data em uma linha DetailsView. O segundo TemplateField exibirá o valor do campo, mas usará um método de Discontinued
formatação para exibir "YES" se Discontinued
for true
, e "NO" caso contrário.
Figura 1: Dois TemplateFields são usados para personalizar a exibição (clique para exibir a imagem em tamanho real)
Vamos começar!
Etapa 1: Associando os dados ao DetailsView
Conforme discutido no tutorial anterior, ao trabalhar com TemplateFields, geralmente é mais fácil começar criando o controle DetailsView que contém apenas BoundFields e, em seguida, adicionar novos TemplateFields ou converter os BoundFields existentes em TemplateFields conforme necessário. Portanto, inicie este tutorial adicionando um DetailsView à página por meio do Designer e associando-o a um ObjectDataSource que retorna a lista de produtos. Essas etapas criarão um DetailsView com BoundFields para cada um dos campos de valor não booliano do produto e um CheckBoxField para um campo de valor booleano (Descontinuado).
Abra a DetailsViewTemplateField.aspx
página e arraste um DetailsView da Caixa de Ferramentas para o Designer. Na marca inteligente do DetailsView, escolha adicionar um novo controle ObjectDataSource que invoca o ProductsBLL
método da GetProducts()
classe.
Figura 2: Adicionar um novo controle ObjectDataSource que invoca o método (clique para exibir a GetProducts()
imagem em tamanho completo)
Para este relatório, remova o ProductID
, SupplierID
, CategoryID
e ReorderLevel
BoundFields. Em seguida, reordene os BoundFields para que os CategoryName
e SupplierName
BoundFields apareçam imediatamente após o ProductName
BoundField. Sinta-se à vontade para ajustar as propriedades e as HeaderText
propriedades de formatação dos BoundFields como achar melhor. Assim como no GridView, essas edições no nível do BoundField podem ser executadas por meio da caixa de diálogo Campos (acessível clicando no link Editar Campos na marca inteligente do DetailsView) ou por meio da sintaxe declarativa. Por fim, desmarque os valores de Height
propriedade e Width
DetailsView para permitir que o controle DetailsView se expanda com base nos dados exibidos e marque a caixa de seleção Habilitar paginação na marca inteligente.
Depois de fazer essas alterações, a marcação declarativa do controle DetailsView deve ser semelhante à seguinte:
<asp:DetailsView ID="DetailsView1" runat="server" AutoGenerateRows="False"
DataKeyNames="ProductID" DataSourceID="ObjectDataSource1" AllowPaging="True"
EnableViewState="False">
<Fields>
<asp:BoundField DataField="ProductName" HeaderText="Product"
SortExpression="ProductName" />
<asp:BoundField DataField="CategoryName" HeaderText="Category"
ReadOnly="True" SortExpression="CategoryName" />
<asp:BoundField DataField="SupplierName" HeaderText="Supplier"
ReadOnly="True" SortExpression="SupplierName" />
<asp:BoundField DataField="QuantityPerUnit"
HeaderText="Qty/Unit" SortExpression="QuantityPerUnit" />
<asp:BoundField DataField="UnitPrice" HeaderText="Price"
SortExpression="UnitPrice" />
<asp:BoundField DataField="UnitsInStock"
HeaderText="Units In Stock" SortExpression="UnitsInStock" />
<asp:BoundField DataField="UnitsOnOrder"
HeaderText="Units On Order" SortExpression="UnitsOnOrder" />
<asp:CheckBoxField DataField="Discontinued"
HeaderText="Discontinued" SortExpression="Discontinued" />
</Fields>
</asp:DetailsView>
Reserve um momento para visualizar a página por meio de um navegador. Neste ponto, você deve ver um único produto listado (Chai) com linhas mostrando o nome do produto, categoria, fornecedor, preço, unidades em estoque, unidades em pedido e seu status descontinuado.
Figura 3: Os detalhes do produto são mostrados usando uma série de BoundFields (clique para exibir a imagem em tamanho real)
Etapa 2: Combinando o preço, as unidades em estoque e as unidades no pedido em uma linha
O DetailsView tem uma linha para os UnitPrice
campos , UnitsInStock
e .UnitsOnOrder
Podemos combinar esses campos de dados em uma única linha com um TemplateField adicionando um novo TemplateField ou convertendo um dos , , e e UnitsOnOrder
BoundFields existentes UnitPrice
UnitsInStock
em um TemplateField. Embora eu pessoalmente prefira converter BoundFields existentes, vamos praticar adicionando um novo TemplateField.
Comece clicando no link Editar campos na marca inteligente do DetailsView para abrir a caixa de diálogo Campos. Em seguida, adicione um novo TemplateField e defina sua HeaderText
propriedade como "Preço e Estoque" e mova o novo TemplateField para que ele seja posicionado acima do UnitPrice
BoundField.
Figura 4: Adicionar um novo TemplateField ao controle DetailsView (clique para exibir a imagem em tamanho completo)
Como esse novo TemplateField conterá os valores atualmente exibidos em , UnitPrice
UnitsInStock
, e BoundFieldsUnitsOnOrder
, vamos removê-los.
A última tarefa desta etapa é definir a ItemTemplate
marcação para o Price and Inventory TemplateField, o que pode ser feito por meio da interface de edição de modelo do DetailsView no Designer ou manualmente por meio da sintaxe declarativa do controle. Assim como acontece com o GridView, a interface de edição de modelo do DetailsView pode ser acessada clicando no link Editar Modelos na marca inteligente. A partir daqui, você pode selecionar o modelo a ser editado na lista suspensa e, em seguida, adicionar quaisquer controles Web da Caixa de Ferramentas.
Para este tutorial, comece adicionando um controle Rótulo ao arquivo .ItemTemplate
Em seguida, clique no link Editar DataBindings da marca inteligente do controle Web de Rótulo e associe a Text
propriedade ao UnitPrice
campo.
Figura 5: Associar a propriedade do Text
rótulo ao campo de dados (clique para exibir a UnitPrice
imagem em tamanho real)
Formatando o preço como uma moeda
Com essa adição, o Label Web control Price and Inventory TemplateField agora exibirá apenas o preço do produto selecionado. A Figura 6 mostra uma captura de tela do nosso progresso até agora quando visualizado por meio de um navegador.
Figura 6: O campo Modelo de preço e estoque mostra o preço (clique para exibir a imagem em tamanho real)
Observe que o preço do produto não está formatado como uma moeda. Com um BoundField, a formatação é possível definindo a HtmlEncode
propriedade como false
e a DataFormatString
propriedade como {0:formatSpecifier}
. Para um TemplateField, no entanto, todas as instruções de formatação devem ser especificadas na sintaxe de vinculação de dados ou por meio do uso de um método de formatação definido em algum lugar dentro do código do aplicativo (como na classe code-behind da página ASP.NET).
Para especificar a formatação da sintaxe de vinculação de dados usada no controle Web Rótulo, retorne à caixa de diálogo DataBindings clicando no link Editar DataBindings da marca inteligente do Rótulo. Você pode digitar as instruções de formatação diretamente na lista suspensa Formato ou selecionar uma das cadeias de caracteres de formato definidas. Assim como a propriedade do BoundField DataFormatString
, a formatação é especificada usando {0:formatSpecifier}
.
Para o campo, UnitPrice
use a formatação de moeda especificada selecionando o valor da lista suspensa apropriada ou digitando {0:C}
manualmente.
Figura 7: Formatar o preço como uma moeda (clique para exibir a imagem em tamanho real)
Declarativamente, a especificação de formatação é indicada como um segundo parâmetro nos Bind
métodos or Eval
. As configurações feitas por meio do Designer resultam na seguinte expressão de vinculação de dados na marcação declarativa:
<asp:Label ID="Label1" runat="server" Text='<%# Eval("UnitPrice", "{0:C}") %>'/>
Adicionando os campos de dados restantes ao TemplateField
Neste ponto, exibimos e formatamos o UnitPrice
campo de dados no campo Modelo de preço e estoque, mas ainda precisamos exibir os UnitsInStock
campos e UnitsOnOrder
. Vamos exibi-los em uma linha abaixo do preço e entre parênteses. A partir da interface de edição de modelos no Designer, essa marcação pode ser adicionada posicionando o cursor dentro do modelo e simplesmente digitando o texto a ser exibido. Como alternativa, essa marcação pode ser inserida diretamente na sintaxe declarativa.
Adicione a marcação estática, os controles Web de rótulo e a sintaxe de vinculação de dados para que o Price and Inventory TemplateField exiba as informações de preço e estoque da seguinte forma:
UnitPrice
(Em estoque / Sob encomenda: UnitsInStock / UnitsOnOrder)
Depois de executar essa tarefa, a marcação declarativa do DetailsView deve ser semelhante à seguinte:
<asp:DetailsView ID="DetailsView1" runat="server" AutoGenerateRows="False"
DataKeyNames="ProductID" DataSourceID="ObjectDataSource1" AllowPaging="True"
EnableViewState="False">
<Fields>
<asp:BoundField DataField="ProductName"
HeaderText="Product" SortExpression="ProductName" />
<asp:BoundField DataField="CategoryName" HeaderText="Category"
ReadOnly="True" SortExpression="CategoryName" />
<asp:BoundField DataField="SupplierName"
HeaderText="Supplier" ReadOnly="True"
SortExpression="SupplierName" />
<asp:BoundField DataField="QuantityPerUnit"
HeaderText="Qty/Unit" SortExpression="QuantityPerUnit" />
<asp:TemplateField HeaderText="Price and Inventory">
<ItemTemplate>
<asp:Label ID="Label1" runat="server"
Text='<%# Eval("UnitPrice", "{0:C}") %>'></asp:Label>
<br />
<strong>
(In Stock / On Order: </strong>
<asp:Label ID="Label2" runat="server"
Text='<%# Eval("UnitsInStock") %>'></asp:Label>
<strong>/</strong>
<asp:Label ID="Label3" runat="server"
Text='<%# Eval("UnitsOnOrder") %>'>
</asp:Label><strong>)</strong>
</ItemTemplate>
</asp:TemplateField>
<asp:CheckBoxField DataField="Discontinued"
HeaderText="Discontinued" SortExpression="Discontinued" />
</Fields>
</asp:DetailsView>
Com essas alterações, consolidamos as informações de preço e estoque em uma única linha DetailsView.
Figura 8: As informações de preço e estoque são exibidas em uma única linha (clique para exibir a imagem em tamanho real)
Etapa 3: Personalizando as informações de campo descontinuadas
A Products
coluna da tabela é um valor de Discontinued
bit que indica se o produto foi descontinuado. Ao associar um DetailsView (ou GridView) a um controle de fonte de dados, os campos de valor booliano, como Discontinued
, são implementados como CheckBoxFields, enquanto os campos de valor não booliano, como ProductID
, ProductName
e assim por diante, são implementados como BoundFields. O CheckBoxField é renderizado como uma caixa de seleção desativada que é marcada se o valor do campo de dados for True e desmarcada caso contrário.
Em vez de exibir o CheckBoxField, talvez queiramos exibir um texto indicando se o produto foi descontinuado ou não. Para fazer isso, podemos remover o CheckBoxField do DetailsView e, em seguida, adicionar um BoundField cuja DataField
propriedade foi definida como Discontinued
. Reserve um momento para fazer isso. Após essa alteração, o DetailsView mostra o texto "True" para produtos descontinuados e "False" para produtos que ainda estão ativos.
Figura 9: As cadeias de caracteres true e false são usadas para exibir o estado descontinuado (clique para exibir a imagem em tamanho real)
Imagine que não quiséssemos que as strings "True" ou "False" fossem usadas, mas sim "SIM" e "NÃO". Essa personalização pode ser realizada com a ajuda de um TemplateField e um método de formatação. Um método de formatação pode incluir qualquer número de parâmetros de entrada, mas deve retornar o HTML (como uma cadeia de caracteres) para injetar no modelo.
Adicione um método de formatação à DetailsViewTemplateField.aspx
classe code-behind da página chamada DisplayDiscontinuedAsYESorNO
que aceita um booliano como parâmetro de entrada e retorna uma cadeia de caracteres. Conforme discutido no tutorial anterior, esse método deve ser marcado como protected
ou public
para ser acessível a partir do modelo.
protected string DisplayDiscontinuedAsYESorNO(bool discontinued)
{
if (discontinued)
return "YES";
else
return "NO";
}
Este método verifica o parâmetro de entrada (discontinued
) e retorna "YES" se for true
, "NO" caso contrário.
Observação
No método de formatação examinado no tutorial anterior, lembre-se de que estávamos passando um campo de dados que poderia conter NULL
s e, portanto, precisávamos verificar se o valor da propriedade do HiredDate
funcionário tinha um valor de banco de dados NULL
antes de acessar a EmployeesRow
propriedade do HiredDate
. Essa verificação não é necessária aqui, pois a Discontinued
coluna nunca pode ter valores de banco de dados NULL
atribuídos. Além disso, é por isso que o método pode aceitar um parâmetro de entrada booleano em vez de ter que aceitar uma ProductsRow
instância ou um parâmetro do tipo object
.
Com esse método de formatação concluído, tudo o que resta é chamá-lo a partir do arquivo .ItemTemplate
Para criar o TemplateField, remova o Discontinued
BoundField e adicione um novo TemplateField ou converta o Discontinued
BoundField em um TemplateField. Em seguida, na exibição de marcação declarativa, edite o TemplateField para que ele contenha apenas um ItemTemplate que invoca o DisplayDiscontinuedAsYESorNO
método, passando o valor da propriedade da Discontinued
instância atualProductRow
. Isso pode ser acessado através do Eval
método. Especificamente, a marcação do TemplateField deve ser semelhante a:
<asp:TemplateField HeaderText="Discontinued" SortExpression="Discontinued">
<ItemTemplate>
<%# DisplayDiscontinuedAsYESorNO((bool)
Eval("Discontinued")) %>
</ItemTemplate>
</asp:TemplateField>
Isso fará com que o DisplayDiscontinuedAsYESorNO
método seja invocado ao renderizar o DetailsView, passando o ProductRow
valor da Discontinued
instância. Como o Eval
método retorna um valor do tipo object
, mas o DisplayDiscontinuedAsYESorNO
método espera um parâmetro de entrada do tipo bool
, convertemos o valor de retorno dos Eval
métodos para bool
. O DisplayDiscontinuedAsYESorNO
método retornará "SIM" ou "NÃO" dependendo do valor recebido. O valor retornado é o que é exibido nessa linha DetailsView (consulte a Figura 10).
Figura 10: Os valores SIM ou NÃO agora são mostrados na linha descontinuada (clique para exibir a imagem em tamanho real)
Resumo
O TemplateField no controle DetailsView permite um maior grau de flexibilidade na exibição de dados do que está disponível com os outros controles de campo e é ideal para situações em que:
- Vários campos de dados precisam ser exibidos em uma coluna GridView
- Os dados são melhor expressos usando um controle Web em vez de texto sem formatação
- A saída depende dos dados subjacentes, como a exibição de metadados ou a reformatação dos dados
Embora TemplateFields permita um maior grau de flexibilidade na renderização dos dados subjacentes do DetailsView, a saída do DetailsView ainda parece um pouco quadrada, pois cada campo é renderizado como uma linha em um HTML <table>
.
O controle FormView oferece um maior grau de flexibilidade na configuração da saída renderizada. O FormView não contém campos, mas apenas uma série de modelos (ItemTemplate
, EditItemTemplate
, HeaderTemplate
e assim por diante). Veremos como usar o FormView para obter ainda mais controle do layout renderizado em nosso próximo tutorial.
Boa programação!
Sobre o autor
Scott Mitchell, autor de sete livros ASP/ASP.NET e fundador da 4GuysFromRolla.com, trabalha com tecnologias da Web da Microsoft desde 1998. Scott trabalha como consultor, instrutor e escritor independente. Seu último livro é Sams Teach Yourself ASP.NET 2.0 em 24 horas. Ele pode ser contatado em mitchell@4GuysFromRolla.com. ou através de seu blog, que pode ser encontrado em http://ScottOnWriting.NET.
Agradecimentos especiais a
Esta série de tutoriais foi revisada por muitos revisores úteis. O revisor principal deste tutorial foi Dan Jagers. Interessado em revisar meus próximos artigos do MSDN? Em caso afirmativo, envie-me uma mensagem para mitchell@4GuysFromRolla.com.