segunda-feira, 28 de novembro de 2011

Capítulo 5: Input Validation and Site Navigation Lição 3: Using Web Parts

Muitos sites hoje possuem uma coleção de componentes que funcionam sozinhos e são auto-suficientes. Por exemplo, é padrão os sites serem divididos por uma barra lateral de navegação, uma barra no topo com o título, uma barra de rodapé, e uma área com notícias. Além disso muitos portais fornecem hoje componentes e relatórios como exemplo sobre o clima ou cotações financeiras.

ASP.NET Web Parts permite ao desenvolvedor criar estes controles. Com estes controles o usuário do site pode escolher se quer visualizar um relatório na tela, ou tem a opção de remover este controle e adicionar outro de informação do clima. Você pode fornecer ao usuário do site uma coleção de controles, para ele definir qual informação ele quer exibir na página que ele esta visualizando.

What Are Web Parts?

Web Part são componentes pré-definidos com funcionalidades que podem ser adicionados no site. Eles possuem uma estrutura definida, gerenciável e um modelo customizado. Alguns desses componentes podem ser movidos dentro do site para ser posicionado conforme a necessidade do usuário. A figura abaixo mostra um controle Web Part sendo posicionado pelo usário.


Você pode utilizar o controle CatalogZone para adicionar um catalogo de controles em sua página, onde o usuário pode adicionar e/ou remover controles Web Part das regiões pré-definidas. A figura abaixo exibe este cenário onde o usuário visualiza uma lista de controles que ele pode adicionar ou remover de sua página.


Páginas de Web Part podem oferecer ao usuário diversas opções de personalização, isso é ótimo quando você desenvolve funcionalidades que abrangem um público amplo. Veja alguns Web Parts comuns que você pode criar:
  • Uma lista de artigos e notícias
  • Um calendário com os eventos
  • Uma lista de WebSites
  • Uma caixa de pesquisa
  • Controles de Navegação
  • Blog
  • Leitores de RSS, etc...
Qualquer controle seja padrão ou controle personalizado pode se tornar um Web Part, e não necessariamente terá que escrever diversas linhas de código, pois o Visual Studio auxilia nesta tarefa.

The WebParts Namespace

O Asp.Net possui vários Web Parts, são 13 os controles disponíveis na ToolBox do Visual Studio. Esses controles e classes podem ser encontrados dentro da Namespace System.Web.UI.WebControls.WebParts. Algumas dessas classes serão discutidas mais profundamente em lições posteriores. A lista a seguir contém as classes mais importantes:
  • WebPartManager: O controle WebPartManager é necessário em todas as páginas que inclui Web Parts. Ele não tem uma representação visual. Em vez disso, ele gerencia todos os controles de Web Parts e seus eventos na página especificada.
  • CatalogPart: O controle CatalogPart fornece a interface de usuário para gerenciar um grupo de Web Parts que podem ser adicionados a uma página de Web Parts. Este grupo é normalmente todo o site (e não apenas específicos para uma determinada página).
  • PageCatalogPart: O controle PageCatalogPart é semelhante ao controle CatalogPart. No entanto PageCatalogPart são apenas grupos dentro de uma página. Se um usuário fechar uma Web Parte ele pode utilizar o PageCatalogPart para adicionar a Web Parte novamente a página.
  • EditorPart: O controle EditorPart permite aos usuários definir personalizações, como a modificação de propriedades de uma Web Part especifica.
  • DeclarativeCatalogPart: Este controle permite você declarar quais controles Web Parte estão disponíveis para adicionar no site.
  • WebPartZone: Controle utilizado para definir regiões que os controles Web Part podem ser hospedados.
  • EditorZone: Controle que definir a região na página onde pode existir os controles EditorPart.
  • CatalogZone: Defini uma região onde pode existir um controle CatalogPart.
Defining Web Part Zones

Você adiciona Web Parts na página colocando-as em zonas. As Zonas definem a área na página onde o usuário ou o desenvolvedor podem adicionar Web Parts. As zonas possuem as propriedades width, height e um local na página. É possível adicionar uma, nenhuma ou várias Web Parts dentro de uma zona. Veja a figura abaixo:


As zonas permitem definir estilos que serão aplicados a todos Web Parts que estiverem dentro dela. Isto é chamado de Web Part’s chrome. O chrome (cromo) inclui estilos de cabeçalho, estilos de menu, definições de borda e outros. As Web Parts que existiverem dentro de uma zona que teve seu chrome definido irá receber os mesmos estilos.

Você cria zonas de Web Parts com o controle WebPartZone. Este controle define a área onde podem ficar Web Parts, este controle também possui a propriedade HeaderText. Nesta propriedade irá o texto que será exibido ao usuário quando a página e a zona estiverem em modo de edição.

Para definir uma zona, você deve adicionar o controle WebPartZone em sua página, para adicionar controles a esta zona, primeiramente você deve adicionar o controle ZoneTemplate dentro de sua WebPartZone, e dentro deo ZoneTemplate você adiciona os demais controles e combinações de sua Web Part. Veja o código:

<asp:WebPartManager ID="WebPartManager1" runat="server">
</asp:WebPartManager>


<asp:WebPartZone ID="WebPartZoneVendor" runat="server" HeaderText="Vendor Aggregate" style="width: 650px; height: auto">
  <ZoneTemplate>

    <!--Add content to the zone-->

  </ZoneTemplate>
</asp:WebPartZone>


Note nas primeiras linhas desse código a existência do controle WebPartManager, apesar dele não ter uma representação visual para o usuário ele é obrigatório no uso de Web Parts.

Creating Web Parts

Existem três principais métodos de criar ASP.Net Web Parts. O primeiro é criar um user control padrão. O segundo é utilizar um controle ASP.Net como uma Label e definir como sua Web Part. O terceiro é criar um controle customizado que herde da classe WebPart, este terceiro será explicado no capítulo 7 "Creating Custom Web Controls", ele é o método mais demora e mais complicado. Os outros dois métodos são mais simples.

Building Web Parts with User Controls

Para criar uma Web Part baseado em um User Control, basta adicionar o User Controle dentro de uma Web Part Zone que o Asp.Net cuida do restante. Como qualquer User Control basta declara-lo em sua página usando a diretiva @ Register, como a seguir:

<%@ Register src="VendorWebPart.ascx" tagname="VendorWebPart" tagprefix="uc1" %>

Após seu User Controle estar registrado basta adicona-lo a uma Web Part Zone, dentro da declaração ZoneTemplate. Veja abaixo:


<asp:WebPartZone ID="WebPartZone2" runat="server" HeaderText="Fabrikam" style="width: 350px; float: left; height: auto;">

  <ZoneTemplate>
    <uc1:VendorWebPart ID="VendorWebPart1" runat="server" title="Fabrikam" />
  </ZoneTemplate>


</asp:WebPartZone>


Creating a Web Part Control from an Existing ASP.NET Control

Seguindo o modelo de utilizar User Controls, é possível utilizar controles padrões do Asp.Net, basta adiciona-los dentro do elemento ZoneTemplate como foi feito acima. Veja o código abaixo:

<asp:WebPartZone ID="WebPartZone1" runat="server" HeaderText="Vendor Aggregate" style="width: 700px; height: auto">
  <ZoneTemplate>
    <asp:Label ID="Label3" runat="server" Text="" title="Vendor Totals">
      <div style="margin-top: 12px; margin-bottom: 20px; line-height: 30px; font-size: 12pt">
        Total Active Users: <a href="#">21</a>
        <br />Total transactions today: <a href="#">166</a>
        <br />Revenue trades to-date: <a href="#">$34,450</a>
      </div>
    </asp:Label>
  </ZoneTemplate>
</asp:WebPartZone>


Enabling Users to Arrange and Edit Web Parts

Web Parts podem ser exibidas de diferentes formas. O modo como ela é exibida é indiferente do que o usuário esta fazendo com a Web Parts ou onde ela esta hospedada naquele momento. É possível alterar o modo de exibição das Web Parts utilizando o controle WebPartManager. Basta definir a propriedade DisplayMode, as opções disponíveis para esta propriedade são:
  • BrowseDisplayMode: É a forma padrão que os usuários navegam;
  • DesignDisplayMode: É o modo que permite aos usuários arrastar a Web Part para diferentes locais;
  • EditDisplayMode: Parecido com o DesignDisplayMode, permite aos usuários arrastar a Web Part, e além disso permite também editar os dados como título, tamanho, direção, aparência da janela e zona, utilizando os controles AppearanceEditorPart e LayoutEditorPart. Para utilizar este modo é necessário adicionar o controle EditorZone a sua página e em seguida o controle AppearanceEditorPart e/ou LayoutEditorPart;
  • CatalogDisplayMode:  Permite ao usuário adicionar Web Parts que você especificou no controle CatalogZone. Para utilizar este modo é necessário ter o controle CatalogZone em sua página;
  • ConnectDisplayMode: Permite ao usuário estabelecer conexões manualmente entre os controles usando o controle ConnectionZone. Por exemplo uma Web Part pode ser ligada para mostrar informações de resumo e detalhe de um relatório. Para utilizar este modo é necessário ter o controle ConnectionZone em sua página.
O código a seguir exibe no clique de um botão como alterar o modo de exibição de uma Web Part:

protected void ButtonEdit_Click(object sender, EventArgs e)
{
  string mode = (string)ViewState["mode"];
  //switch modes
  if (mode == "browse")
  {
    ViewState["mode"] = "edit";
    ButtonEdit.Text = "Done";
    WebPartManager1.DisplayMode = WebPartManager1.SupportedDisplayModes["Catalog"];
  }
  else
  {
    ViewState["mode"] = "browse";
    ButtonEdit.Text = "Edit";
    WebPartManager1.DisplayMode = WebPartManager1.SupportedDisplayModes["Browse"];
  }
}


Repare que é usado a coleção SupportedDisplayModes para definir qual modo será exibido. Neste código vale explicar que o valor da ViewState foi salvo no evento PageLoad.

Connecting Web Parts

Uma possibilidade poderosa da Web Part é a conexão entre Web Parts. Para entender o uso, imagine o cenário onde esta desenvolvendo uma aplicação para controle da folha de pagamento dos funcionários, onde você tem:
  • A Web Part principal onde o usuário navega entre os funcionários.
  • Uma Web Part que exibe um gráfico das horas extras pagas ao funcionário.
  • Uma Web Part que exibe um gráfico de pizza que exibe o valor da folha de pagamento, benefícios e pensões que se encaixam no perfil global do funcionário.
  • E uma Web Part que compara o salário do funcionário com outros funcionários do mesmo cargo.
Com a conexão de todas Web Parts o usuário irá selecionar o funcionário uma única vez e todas as outras Web Parts irão ter suas informações atualizadas automaticamente.

Outro cenário é o desenvolvimento de um portal onde você tem várias Web Parts com informações distintas como clima, notícias locais e localização de bares. Porém todas elas necessitam do CEP para localizar essas informações, o usuário do portal irá informar o CEP uma única vez e todas as Web Parts irão se comunicar para ter acesso a este CEP.

Creating a Static Connection

Conexões podem ser estáticas ou dinâmicas. Se a conexão for estática, estabelecidade pelo desenvolver no momento de desenvolvimento ela não poderá ser alterada ou excluida pelo usuário. Conexões estáticas envolvem um Provider e um ou mais WebParts consumidores. Veja os passos para se criar os controles, tanto o provider como o consumidor e estabelecer uma conexão entre eles.

Primeiro Passo: Criar o WebParte provider.
O WebPart provider pode derivar da classe WebPart ou ser um user control. Você deve criar no seu WebPart um método público que tenha o atributo ConnectionProvider. Este método deve retornar o valor que o WebPart consumidor irá receber. Veja o código:

public partial class Provider : System.Web.UI.UserControl
{
  string _textBoxValue = "";
  

  [ConnectionProvider("TextBox provider", "GetTextBoxValue")]
  string GetTextBoxValue()
  {
    return _textBoxValue;
  }
 

  protected void Button1_Click(object sender, EventArgs e)
  {
    _textBoxValue = TextBoxProvider.Text;
  }
}


Passo 2: Criar o WebPart consumidor.
Assim como o provider pode herdar de WebPart ou ser um user control. É necessário criar um método público que possua o atributo ConnectionConsumer que recebe o mesmo tipo que o método do ConnectionProvider retorna. Veja o código:

public partial class Consumer : System.Web.UI.UserControl
{
  [ConnectionConsumer("TextBox consumer", "ShowTextBoxValue")]
  void ShowTextBoxValue(string textBoxValue)
  {
    LabelConsumer.Text = textBoxValue;
  }
}


Passo 3: Crie uma WebPage e adicione o controle WebPartManager, em seguida adicione o container WebPartZone.

Passo 4: Adicione seus WebPart ao WebPartZone, tanto o provider como o consumidor:

<asp:WebPartZone ID="WebPartZoneProvider" runat="server" Height="400px" Width="300px">
  <ZoneTemplate>
    <uc1:Provider ID="Provider1" runat="server" title="Provider" />
    <uc2:Consumer ID="Consumer1" runat="server" title="Consumer" />
  </ZoneTemplate>
</asp:WebPartZone>


O próximo passo é estabelecer a conexão entre os dois controles. Adicione o elemento <StaticConnections> ao WebPartManager e dentro deste elemento adicione o controle WebPartConnection para declarar sua conexão.

O controle WebPartConnection deve ter a propriedade ID, a propriedade ProviderID identifica o controle provider, ProviderConnectionPointID identifica o método do provider, ConsumerID identifica o controle consumidor, ConsumerConnectionPointID identifica o método no consumidor. Veja o código:

<asp:WebPartManager ID="WebPartManager1" runat="server">
  <StaticConnections>
    <asp:webPartConnection
        ID="conn1"
        ProviderID="Provider1"
        ProviderConnectionPointID="GetTextBoxValue"
        ConsumerID="Consumer1"
        ConsumerConnectionPointID="ShowTextBoxValue" />
  </StaticConnections>
</asp:WebPartManager>


Repare que você deve criar um controle WebPartConnection para cada par de controle conectado.

Enabling Dynamic Connections

Conexões dinâmicas podem ser estabelecidades pelo usuário. Para permitir esta ação você precisa adicionar o controle ConnectionsZone em sua página.
Para permitir que os usuários criem ou parem conexões, siga os seguintes passos:
  1. Crie uma página com um provider e um consumidor como explicado anteriormente.
  2. Opcionalmente, estabeleça uma conexão estática entre o provider e o consumidor. Esta será uma conexão padrão que estará sempre disponível para o usuário, mas ele pode modificar criar ou parar outras conexões dinâmicas.
  3. Adicione o controle ConnectionsZone em sua página.
  4. Adiciona o controle para permitir que o usuário entre no Modo Connect como explicado anteriormente em "“Enabling Users to Arrange and Edit Web Parts".
Establishing Dynamic Connections Among Web Parts

Quando um usuário acessar sua página ele pode alterar para o modo de conexão e utilizar o controle ConnectionsZone para editar as conexões. Veja os passsos:
  1. Altere o modo de visualização para connect.
  2. O menu do WebPart irá aparecer entre o provider e consumidor, clique em Connect no menu, veja a imagem:

        3. Irá aparecer o objeto ConnectionsZone:

        4.Caso já exista uma conexão, clique em Disconnect para fechar esta conexão. Em seguida clique em Create A Connection To A Consumer, selecione o consumidor e clique em Connect:

        5.Quando finalizar a edição das conexões clique em Close. As WebParts estarão conectadas como se fosse feito estaticamente.

Personalizing Web Parts

WebParts suportam personalização. A personalização permite que as alterações feitas sejam armazenadas por cada usuário, permitindo que ele visualize a página da mesma forma na próxima visita. Personalização de WebParts dependem dos cookies do navegador do usuário, através das informações dos cookies, serão buscadas as personalizaçãoes feitas no banco de dados. Armazenada essas informações por usuário, normalmente você vai querer utilizar autenticação, mas isso não é necessário.

Enabling Personalization for Custom Controls

Para permitir esta personalização nos controles de WebPart é necessário definir no método público do controle o atributo Personalizable, veja como:

[Personalizable]
public string PostalCode
{
  get
  {
    Return _postalCode;
  }
  set
  {
    _postalCode = value;
  }
}

Enabling Shared Personalization

A personalização de WebParts são habilitadas por padrão e os usuários autenticados, conseguem personalizar uma WebPart sem qualquer configuração especial. Porém essas personalizações são feitas a nível de usuário, onde cada usuário visualiza somente sua mudança.
Caso queria dar permissão para algum usuário, como o webmaster do site altere a personalização de qualquer usuário, isto é possível. Basta habilitar a personalização compartilhada no web.config.

Dentro da sessão <system.web>, adicione a sessão <authorization>, então adicione o elemento <allow> para especificar qual usuário ou usuário tem acesso a personalização compartilhada.

<authorization>
  <allow verbs="enterSharedScope" users="SomeUserAccount" roles="admin" />
</authorization>

Desta forma os usuários podem alterar uma personalização e essas mudanças serão vistas por outros usuários.
Disabling Personalization for a Page

Caso queria desabilitar a personalização em alguma página, basta definir a propriedade WebPartManager.Personalization.Enabled para false. Veja como:

<asp:webPartManager ID="webPartManager1" runat="server">
  <Personalization Enabled="False" />
</asp:webPartManager>

sexta-feira, 4 de novembro de 2011

Capítulo 5: Input Validation and Site Navigation Lição 2: Performing Site Navigation

Os sites devem prover aos usuários formas simples de navegação. Os desenvolvedores devem controlar como o usuário navega em seu site e até mesmo as execuções de PostBack em suas páginas. Esta lição mostra ferramentas que auxiliam nessas tarefas.

Is Page Navigation Necessary?

Navegação entre páginas é o processo de passagem de uma página para outra. Entretanto com alguns recursos que temos atualmente como Asynchronous JavaScript e XML (AJAX), você pode executar vários processos na mesma página, sem a necessidade de ficar trocando de páginas. Você não precisa mais ficar trocando de páginas para executar algo, pode fazer isso com um PostBack para o servidor ou até mesmo do lado do cliente. Claro que existem cenários que será necessário o armazenamento em banco de dados ou coisas do tipos.

Mas é importante que saiba que hoje dependendo do cenário pode fugir de metodologias antigas de navegação entre páginas para gerenciar processos.

Choosing a Method to Navigate Pages

O asp.net possui algumas maneiras de navegar entre as páginas. É bom conhecer detalhamente as diferenças entre cada maneira. Veja as opções disponíveis:
  • Client-side navigation: um código cliente permite que seja solicitado uma nova página. Este código solicita uma nova página com base no evento de um hyperlink ou a execução de um JavaScript;
  • Cross-page posting: um controle e um formulário são configurados para enviar um PostBack para uma página diferente da que faz a solicitação;
  • Client-side browser redirect: um código servidor, envia uma mensagem ao navegador solicitando uma página diferente;
  • Server-side transfer: um código servidor solicita uma transferência para uma página diferente;
Client-Side Navigation

A forma mais simples de permitir a navegação entre as páginas do seu site é utilizar um controle de Hyperlink, basta definir a propriedade NavigateUrl com o destino do link. O controle asp.net Hyperlink quando renderizado, gera o elemento html <a>, veja o exemplo:


HyperLink Control: Source
<asp:HyperLink ID="HyperLink1"runat="server" NavigateUrl="~/NavigateTest2.aspx">Goto NavigateTest2</asp:HyperLink>

HyperLink Control: Rendered HTML
<a id="HyperLink1" href="NavigateTest2.aspx">Goto NavigateTest2</a>

No exemplo acima quando este link for clicado o navegador requisitará a página NavigateTest2.aspx, neste caso não estamos passando nenhum informação de dados na URL, mas podemos utilizar a querystring para fornecer algumas informações caso necessário.

Outra forma de se fazer o mesmo processo é via javascript. O objeto document representa o formulário atual no javascript. Podemos definir a propriedade location para requisitar a nova página. Veja o exemplo:

<input id="Button1" type="button" value="Goto NavigateTest2" onclick="return Button1_onclick()" />

Quando o botão for clicado ele irá acionar uma função javascript chamada Button1_onclick(), esta função deve ser criada dentro da tag <head>:

<script language="javascript" type="text/javascript">
  function Button1_onclick() {
    document.location="NavigateTest2.aspx";
  }
</script>


Cross-Page Posting

 Cross-Page Posting, ou postagem entra páginas é frequentamente usado em cenários onde por exemplo existem 2 páginas, a primeira com um formulário e a segunda utilizada para exibir os dados. Na primeira basta definir a propriedade PostBackUrl de um botão com o nome da segunda página, chamada de página de processamento. Esta página recebe o PostBack com os dados da primeira página para executar o processamento.


Nesta página de processamento é possível validar se ocorreu o PostBack na página anterior enviando uma coleção de dados. Através da propriedade Page.PreviousPage, você valida se ocorreu ou não o PostBack, veja o exemplo a baixo:


protected void Page_Load(object sender, EventArgs e)
{
  if(Page.PreviousPage == null)
  {
    LabelData.Text = "No previous page in post";
  }
  else
  {
    LabelData.Text = Server.HtmlEncode(((TextBox)PreviousPage.FindControl("TextBox1")).Text);
  }
}


Accessing Posted Data as Strongly Typed Data

É possível acessar propriedades com tipos definidos entre páginas, sem a necessidade de chamar o FindControl ou executar alguma conversão. Você pode criar uma propriedade pública na sua primeira página que terá seu valor acessado pela segunda página. Além de criar esta propriedade na primeira página, só é necessário adicionar a diretira PreviousPageType na segunda página, a página de processamento.

Imaginando o mesmo cenário do exemplo anterior, na primeira página chamada DataCollection.aspx temos um textbox e um botão onde sua propriedade PostBackUrl foi definida como "~/ProcessingPage.aspx". Crie a seguinte propriedade na primeira página:

public string PageData
{
  get { return TextBox1.Text; }
}


Para ter acesso a esta propriedade na página de processamento, adicionar a diretiva PreviousPageType, como a seguir:
 <%@ PreviousPageType VirtualPath="~/ProcessingPage.aspx" %>

Na página de processamento temos uma label que irá exibir a propriedade da página anterior:

protected void Page_Load(object sender, EventArgs e)
{
  if (PreviousPage == null)
  {
    LabelData.Text = "No previous page in post";
  }
  else
  {
    LabelData.Text = PreviousPage.PageData;
  }


Acessando a propriedade PreviousPage.PageData conseguirá ter acesso ao valor do textbox da página anterior. Desta forma é possível declarar outras propriedade, fugindo da necessidade de conversões ou a chamada ao FindControl.


Client-Side Browser Redirect

Este é o famoso Response.Redirect que usamos. Diversas vezes precisamos redirecionar o usuário a uma outra página com base em uma ação que ele executou no site. O objeto Page.Response contém o método Redirect que faz isso.

O Redirect é executado do lado do servidor, porém não é um PostBack, ele ocorre após o PostBack. Considere o exemplo que você possui uma página SubmitOrder.aspx que contém um botão que irá ocasionar um PostBack no servidor, após este PostBack você irá redirecionar o usuário a página OrderDetails.aspx

protected void ButtonSubmit_Click(object sender, EventArgs e)
{
  Response.Redirect("~/OrderDetails.aspx");
}


O redirecionamento ocorre por que é enviado para o browser o código de resposta 302 junto com o novo endereço url. Assim a url do navegador é alterada e o usuário é redirecionado para a nova página. É necessário utilizar em momento certos, pois como é executado do lado do servidor, existe um "custo" para realizar esta operação.

A propriedade PreviousPage não é alimentado neste caso, para acessar dados da página anterior é necessário utilizar outras fomas como armazenar em Cookie, variáveis de Sessão ou via QueryString.

Server-Side Transfer

Você pode usar a Server.Transfer para forçar o Asp.Net a processar uma página diferente da informada na URL sem a necessidade de uma nova requisição no browser. Por exemplo, se você acessa uma página page1.aspx e nessa page1.aspx ela executa Page.Server.Transfer("page2.aspx") o Asp.Net irá processar e exibir a página page2.aspx, porém para o usário isso será invisivel e na URL do navegador continuará aparecendo page1.aspx. Exemplo de código:

protected void Button1_Click(object sender, EventArgs e)
{
  Server.Transfer("~/OrderProcessing.aspx", false);
}


O método Transfer possui uma sobrecarga que possui um parâmetro boleano chamado preserveForm. O valor informado para este parâmetro indica se você quer manter seu formulário e os dados de query string. É possível acessar a propriedade PreviousPage durante a transferência. Se ocorrer alguma excessão na nova página que foi chamada, o processo irá retornar a página original.

Este capítulo faz questão de salientar que o uso do Server.Transfer é mais importante do que parece. Ele é útil quando você quer por exemplo navegar entre diferentes páginas no seu site, mas exibir apenas uma URL ao usuário.

O "poder" do Server.Transfer esta em você alternar suas páginas sem que o usuário veja isto.


Using the Site Map Web Server Control


Já foram explicada técnicas de como ajudar o usuário movimentado-o entre as páginas. Um quesito importante no seu website é uma estrutura sólida de navegação que auxilia e facilita o usuário na navegação em seu site. O Asp.Net possui uma forma de gerenciar sua estrutura e fornece-la ao usuário.

Você pode gerenciar e documentar a estrutura do seu site usando um site map. O site map no Asp.Net é um arquivo Xml que contém a estrutura e a hierarquia do seu site, ele é utilizado para popular controles de navegação como NavigationMenu, SiteMapPath, e TreeView.

Para adicionar um site map clique com o botão direito no seu projeto e selecione Add New Item | Site Map. Será criado um arquivo xml com a extensão .sitemap. Você adiciona nós no site map adicionando elementos <siteMapNode>. Cada elemento desse possui o atributo title que será exibido ao usuário, atributo url que contém a página que irá navegar e o atributo description que contém uma definição da página. Exemplo de sitemap:

<?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
<siteMapNode url="~/Default.aspx" title="Home" description="">
<siteMapNode url="~/Catalog.aspx" title="Our Catalog" description="">
<siteMapNode url="~/ProductCategory.aspx" title="Products" description="" />
<siteMapNode url="~/Product.aspx" title="View Product" description="" />
</siteMapNode>
<siteMapNode url="~/Cart.aspx" title="Shopping Cart" description="" />
<siteMapNode url="~/Account.aspx" title="My Account" description="">
<siteMapNode url="~/SignIn.aspx" title="Login" description="" />
<siteMapNode url="~/PassReset.aspx" title="Reset Password" description="" />
<siteMapNode url="~/AccountDetails.aspx" title="Manage Account" description="">
<siteMapNode url="~/Profile.aspx" title="Account Information" description="" />
<siteMapNode url="~/OrderHistory.aspx" title="My Orders" description="">
<siteMapNode url="~/ViewOrder.aspx" title="View Order" description="" />
</siteMapNode>
</siteMapNode>
</siteMapNode>
<siteMapNode url="~/AboutUs.aspx" title="About Us" description="" />
<siteMapNode url="~/Privacy.aspx" title="Privacy Policy" description="" />
<siteMapNode url="~/ContactUs.aspx" title="Contact Us" description="" />
<siteMapNode url="~/MediaKit.aspx" title="Media Relations" description="" />
</siteMapNode>
</siteMap>


Using the SiteMap Class

A classe SiteMap permite acessar em tempo de execução através do código de programação a hierarquia do seu site. Existem duas propriedades primárias RootNode e CurrentNode ambas retornam uma instância SiteMapNode. O objeto SiteMapNode representa um nó no seu arquivo sitemap e nele você tem acesso as propriedades antes listadas: title, url e description. Para ter acesso aos nós na hierarquia você deve utilizar as propriedades ParentNode, ChildNodes, NextSibling, e PreviousSibling na instância do SiteMapNode. O código abaixo mostra quem é o nível superior da página que esta sendo acessada:

protected void Button1_Click(object sender, EventArgs e)
{
  Response.Redirect(SiteMap.CurrentNode.ParentNode.Url);
}


Displaying Site Map Information to Users

O sitemap é apenas um arquivo xml com informações, para exibir esses dados ao usuário são necessários controles de navegação. Esses controles de navegação podem conectar diretamente em seu arquivo site map, vou conectar no controle SiteMapDataSource.

O SiteMapDataSource é um controle simples designado a permitir que o programador acesse o arquivo site map. Este controle é usado como fonte de dados de controles de navegação. Para usar este controle basta arrasta-lo para sua página e ele automaticamente irá conectar no site map definido no seu site.

Existem dois atributos que podem ser usados para configurar o controle SiteMapDataSource. ShowStartingNode você define como false caso não queira que o usuário visualize o nós raíz do seu site. O segundo é o StartingNodeOffset, é útil quando estiver usando um controle de sub-navegação e queira mostrar apenas partes da navegação. Veja como fica o código do controle:

<asp:SiteMapDataSource ID="SiteMapDataSource1" runat="server" StartingNodeOffset="0" ShowStartingNode="False" />

Assim como o site map o controle SiteMapDataSource não tem representação visual para o usuário, é necessário utilizar algum controle de navegação que faça isso. Existem três principais controle de navegação no asp.net: Menu, TreeView, e SiteMapPath.

O controle Menu como o nome ja diz é para exibir a estrutura do seu site como um menu, o usuário conseguirá navegar desde as páginas raíz até seus últimos níveis. O Menu possui várias propriedade que envolvem principalmente layout e estilo. Mas existe dois atributos que o livro foca, é o DataSourceId e Orientation. No DataSourceId você irá definir o nome do controle DataSource, você pode informar o nome do SiteMapDataSource que adicionou em sua página. Já Orientation é para definir se irá mostrar o menu de forma veritical ou horizontal. Veja o código abaixo:

<asp:Menu ID="Menu1" runat="server" DataSourceID="SiteMapDataSource1" MaximumDynamicDisplayLevels="5" Orientation="Horizontal">
</asp:Menu>


Com base no site map que foi postado nesta lição, o resultado deste menu será:


Já o controle TreeView exibe a estrutura do site no formato de uma "árvore", onde o usuário poderá navegar entre os itens até chegar ao último nível e selecionar a página desejada, para utilizar o SiteMapDataSource como fonte de dados, deve ser feito o mesmo processo do controle Menu. Veja como fica a TreeView:


O último controle é o SiteMapPath, ele permite ao usuário saber em qual página ele esta, e quais são os níveis anteriores para chegar nesta página. Este controle cria um rastro de navegação até a página que o usuário esta utilizando. Adicionando este controle a sua página ele automaticamente irá utilizar o arquivo site map, não é necessário configurar seu DataSource como nos outros controles anteriores. Veja como fica seu resultado:

domingo, 25 de setembro de 2011

Capítulo 5: Input Validation and Site Navigation Lição 1: Performing Input Validation

Este capítulo demonstra 2 recursos do asp.net.

O primeiro é a validação automática de entrada de dados em formulários web, podendo essas validações serem geradas como javascript melhorando assim o desempenho da resposta ao usuário. E também por segurança componentes que fazem validação do lado do servidor.

O outro recurso deste capítulo é sobre a navegação facilitada ao usuário com o uso de Web Parts.

Lesson 1: Performing Input Validation

Nesta lição serão apresentados controles que irão facilitar no momento de fazer validações de entrada de dados em formulários web.

Understanding the Validation Framework

A validação de dados é algo comum e rotineiro para desenvolvedores. O asp.net possui ferramentas que facilitam a criação dessas valições de forma rápida e com poucos códigos.

Existem 2 cenários que podem ser utilizados. Você pode utilizar a validação do lado do cliente, desta forma os controles irão gerar códigos javascripts que são rodados no browser, evitando assim que seja feita a comunicação com o servidor. Ou seja, antes mesmo do usuário clicar no botão "enviar/gravar" ele já terá uma resposta se esta preenchendo o formulário de maneira correta. Porém este é um cenário que não é totalmente seguro, usuário maliciosos podem facilmente "boicotar" essa validações que rodam do lado do cliente.

Porém o asp.net fornece ferramentas que fazem as mesmas validações do lado do servidor, garantindo assim maior segurança dos dados.

Adding Validation Controls to Your Page

Você pode localizar os controles de validação na ToolBox do Visual Studio, você irá proceder da mesma forma com que faz com outros controles. Siga os seguintes passos para adicionar uma validação a sua página:
  1. Abra a página no Design view e abra a ToolBox. Adicione um controle de entrada de dados que será validado, como um TextBox ou RadioButtonList.
  2. Vá até a aba Validation da Toolbox. Arraste um RequiredFieldValidator para próximo do TextBox que será validado como campo obrigatório.
  3. Defina a propriedade ID do RequiredFieldValidator com um nome semelhante do ID definido ao TextBox, desta forma seu código ficará mais facil de ser entendido. Por exemplo, caso seu TextBox tenha a propriedade ID dfinida como NomeTextBox, defina o ID do RequiredFieldValidator como NomeTextBoxValidator.
  4. Defina a propriedade ControlToValidate do seu RequiredFieldValidator com o ID do seu TextBox, neste caso, NomeTextBox.
  5. Defina a propriedade ErrorMessage, esta será a mensagem exibida ao usuário, utilize algo que facilite o entendimento do usuário. É comum exibir essas mensagens todas em um único controle chamado ValidationSummary.
  6. Defina a propriedade Text do TextBox para algo que "avise" o usuário que a validação falhou. Caso você utilize um ValidationSummary, pode definir a propriedade Text com um asterisco (*).
  7. Caso não queria exibir nada na propriedade Text é recomendado utilize a propriedade tooltip com uma mensagem curta e similar a mensagem de erro que é exibida no ValidationSummary, desta forma quando o usuário levar o cursor ao TextBox irá ver que a validação falhou.
  8. Caso não queira que seja exibida mensagem ao usuário se a validação falhe, defina a propriedade Display para None. Se deseja exibir a mensagem pro usuário, defina a propriedade como Static, porém como é uma mensagem estatica, defina uma mensagem em branco que irá aparecer antes de ocorrer a validação. Caso contrário deixe a propriedade como Dynamic para que o asp.net formate a saída do texto caso ocorra uma falha de validação;
  9. Opcionalmente utilize o controle ValidationSummary para exibir várias mensagem de erros de validação. É muito útli quando possui vários controles que são validados e dificulta posicionar todas as mensagens de forma separada em sua página. É interessante que este controle seja posicionado próximo ao botão de submit ou no topo do formulário. Você pode definir a propriedade ShowMessageBox para true, onde este controle irá exibir um PopUp com as mensagens de erros de validação.
Server-Side Validation

Os controles de validação trabalham em conjunto com o objeto Pag, para garantir que os dados do clientes sejam válidos quando chegar ao servidor. A classe Page possui a propriedade Validators que contém que é uma coleção de todos os validadores da página. A classe possui também um método chamado Validate que pode ser executado para verificar cada controle de validação.

O Asp.net chama o método Validate automaticamente após o Load da página. Portando você pode descobrir se a página é válida através da propriedade Page.IsValid.

Client-Side Validation

O Asp.net escreve os códigos de validação do lado do cliente quando você utiliza um controle de validação. O Asp.net escreve os códigos javascript que são executados quando o usuário sai de um campo que possui algum tipo de validação. 

Toda vez que um controle que possui uma validação perder o foco será disparado a validação javascript podendo assim exibir uma mensagem de aviso ao usuário. Você pode usar a propriedade SetFocusOnError para definir um foco ao controle quando sua validação falhar, desta forma o usuário so conseguirá sair deste campo quando entrar com dados válidos.

Determining When to Cause Validation

Utilizar a validação do lado do cliente é útil pois evita o envio da página para o servidor caso a página não seja válida. Porém isto pode ocasionar problemas em algumas situações. Por exemplo, caso você tenha um botão de Ajuda ou de Cancelar, estes botões não conseguiram disparar seus eventos para o servidor enquanto a página não estiver totalmente válida.

Para estes casos, existe a propriedade CausesValidation. Esta propriedade pode ser definida como false quando deseja que algum botão seja executado sem passar pela validação, pode ser usados em botão de Limpar, Voltar, etc...

Using Validation Groups

Existem cenários onde é necessário validar somente parte dos controles da sua página. Você pode agrupar seus controles de uma forma que serão válidados por grupos. Os controles de validação possuem a propriedade ValidationGroup que recebe uma string, esta string deve ser comum aos controles que deseja validar ao mesmo tempo.


Isso é possível por que o método Validate da página possue uma sobrecarga que recebe uma string como parâmetro, que é o ValidationGroup. Esta sobrecarga é executada quando ocorre um postback na página causando a validação dos controles.

O objeto Page possue também o método GetValidators que recebe uma string como parâmetro, neste caso devemos informar o ValidationGroup, e este método retornará todos os controles que são validados neste ValidationGroup.

Understanding the RequiredFieldValidator Control

O controle RequiredFieldValidator é utilizado para forçar que o usuário informe ou altere a informação de algum controle. O RequiredFieldValidator não valida informações como data, números inteiros e outros. Ele é utilizado para forçar o usuário a preencher os dados.

Além de obrigar o usuário a preencher o text de um textbox por exemplo, você definir um valor padrão para a propriedade text do seu controle, obrigando o usuário a alterar este valor. O RequiredFieldValidator possue a propriedade InitialValue, o valor informado para esta propriedade será considerado inválido caso o usuário não altere.

Exemplo: Você possui um dropdownlist de Estado, onde o primeiro valor do seu dropdownlist é "Selecione um estado...", você pode informar este valor para o InitialValue do seu RequiredFieldValidator forçando o usuário a escolher outra opção.


Using the CompareValidator Control

O controle CompareValidator permite validação de comparações, usando operadores como maior ou menor para comparar entrada de dados do usuário em um ou diferentes controles.

O CompareValidator pode ser usado para validar se o tipo de dados esta correto em um controle, como por exemplo se é uma data ou um número. Para este propósito você deve definir a propriedade Type para um tipo válido que será verificado. Se o objetivo for somente verificação de dados, pode ser definida a propriedade Operator para DataTypeCheck.

A imagem abaixo mostra a janela de propriedade do controle CompareValidator.




O CompareValidator utiliza a propriedade ValueToCompare para definir uma constante que será usada para fazer a comparação. Como exemplo, se você deseja que o usuário informe uma data superior a 1900, você deve definir a propriedade ValueToCompare para 1/1/1900 e definir a propriedade Operator, onde terá as seguintes opções: Equal, NotEqual, GreaterThan, GreaterThanEqual, LessThan, LessThanEqual, ou DataTypeCheck. Neste caso deve definir GreaterThanEqual (maior ou igual que). 


Também é possível utilizar este controle para validar duas datas, se uma é maior que a outra, ou validar se dois controles tem o mesmo valor, existe uma série de validações que podem ser criadas com o CompareValidator.


Using the RangeValidator Control


Muitas vezes temos a necessidade de validar um valor dentro de uma variação. Por exemplo, podemos querer que um campo de data seja informado com o Ano que seja o mesmo que o Ano corrente. Para este tipo de validação usamos o RangeValidator, ele possui duas propriedade principais, MinimumValue e MaximumValue, o nome delas já são bem intuitivos, outro propriedade é a Type que define qual o tipo de dados irá validar. 

No exemplo a baixo o controle recebe o valor do ano corrente como valor máximo e 1900 como valor minimo para não permitir que o usuario informe uma data fora deste intervalo.


protected void Page_Load(object sender, EventArgs e)
{
  if (!IsPostBack)
  {
    RangeValidatorSalesDate.MinimumValue = "1990";
    RangeValidatorSalesDate.MaximumValue = DateTime.Now.Year.ToString();
  }
}


Using the RegularExpressionValidator Control 

Este controle efetua suas validações através de expressões regulares. Uma expressão regular é uma série de combinações de caracteres que são usadas para identificar sequências de caracteres simples ou complexas. O controle possui a propriedade ValidationExpression onde você deve informar sua expressão regular.


Expressões regulares são complexas, porém não são exigidas nesta certificação, por isso o assunto não é muito discutido. Mas em todo o caso, o visual studio possui algumas expressões regulares pré-definidas neste controle, como por exemplo, validação de endereço de e-mail ou uma url válida. Veja na imagem a baixo.



The CustomValidator Control


Apesar dos diversos controles de validação que o asp.net fornece, pode acontecer de você precisar de algum outro tipo de validação. Para estes casos, você deve utilizar o controle CustomValidator. A validação deste controle é baseada no código em que o desenvolvedor cria. Você tem a opção de utilizar a validação com javascript para rodar do lado do cliente, ou fazer via c# para rodar do lado do servidor.


Custom Client-Side Validation

Como ja falado diversas vezes, a validação do lado do cliente acontecerá bem mais rápido para quem estiver utilizando sua página.
O primeiro passo é escrever sua validação do lado cliente, você deve possui um método com a seguinte assinatura:

function ClientFunctionName(source, arguments)

Você pode renomear o método conforme sua necessidade, porém os parâmetros de entrada não podem ser modificados. Após este método ser referenciado em seu controle, o framework de valiação irá executar seu método automaticamente. Quando a função de validação for executada, o parâmetro chamado source irá conter uma referência ao controle de validação que este sendo executado. Já o parâmetro arguments tem a propriedade chamada Value que possue os dados a serem validados.


Em seguida deve escrever seu código de validação, e definir a propriedade arguments.IsValid para true ou false. E para finalizar basta definir a propriedade ClientFunctionName de seu controle, com o nome de sua função.


No exemplo a seguir, existe o seguinte cenário: você possui em sua página um controle TextBox, um botão para confirmar os dados, um ValidationSummary para exibir as mensagens de erro, e um RequiredFieldValidator para obrigar o usuário a informar uma nova senha no TextBox. Além disso tem o CustomValidator que irá fazer a seguinte validação nos dados do textbox, é um campo de senha que deve ter entre 6 e 14 caracteres, deve conter pelo menos 1 letra maiscula, uma minuscula, e pelo menos 1 número. Veja como fica o código:


<%@ Page Language="VB" AutoEventWireup="false" CodeFile="NewPassword.aspx.vb" Inherits="NewPassword" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/ xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head id="Head2" runat="server">
        <title>Change Password</title>
    </head>
    <body style="font-family: Arial">
        <form id="form1" runat="server">
            <div>
                <table width="400">
                    <tr><td colspan="2" style="font-size: x-large">Change Password</td></tr>
                    <tr>
                        <td colspan="2">
                            <asp:ValidationSummary ID="ValidationSummary1" runat="server" />
                        </td>
                    </tr>
                    <tr>
                        <td width="190" align="right" valign="middle">New password:</td>
                        <td width="210" valign="middle">
                            <asp:TextBox ID="NewPasswordTextBox" runat="server" TextMode="Password"></asp:TextBox>
                            <asp:RequiredFieldValidator ID="RequiredFieldValidatorPassword" runat="server" ErrorMessage="Please enter a valid password" text="*" ToolTip="Please enter a valid password" ControlToValidate="NewPasswordTextBox"></asp:RequiredFieldValidator>
                            <asp:CustomValidator ID="NewPasswordCustomValidator" runat="server" Text="*" ToolTip="Password must be between 6-14 characters and include 1 capital letter, 1 lowercase letter, and 1 number" ErrorMessage="Password must be between 6-14 characters and include 1 capital letter, 1 lowercase letter, and 1 number" ControlToValidate="NewPasswordTextBox" ClientValidationFunction="ValidatePassword"></asp:CustomValidator>
                        </td>
                    </tr>
                    <tr>
                        <td></td>
                        <td><asp:Button ID="ButtonSubmit" runat="server" Text="Submit" /></td>
                    </tr>
                </table>
            </div>
        </form>
    </body>
</html>


O próximo passo é adicionar o código javascript com a função de validação. A função chama ValidatePassword. Observe que a assinatura do método segue o padrão mostrado anteriormente, e que como é definida o arguments.IsValid.

<script language="javascript" type="text/javascript">
    function ValidatePassword(source, arguments) {
        var data = arguments.Value.split('');
      
        //start by setting false
        arguments.IsValid = false;
      
        //check length
        if(data.length < 6 || data.length > 14) return;
      
        //check for uppercase, lowercase, and number
        var uc = false; var lc = false; var num = false;
      
        for (var c in data) {
            if (data[c] >= 'A' && data[c] <= 'Z') {
                uc = true;
            } else if (data[c] >= 'a' && data[c] <= 'z') {
                lc = true;
            } else if (data[c] >= '0' && data[c] <= '9') {
                num = true;
            }
      
            if (uc && lc && num) {
                arguments.IsValid = true;
                break;
            }
        }
    }
</script>


Como último passo basta definir a propriedade ClientValidationFunction com o nome da função javascript, no momento do teste, assim que o foco sair do TextBox, a validação será executada.


Custom Server-Side Validation

O CustomValidador pode ser usado para validar os dados do lado do cliente, do servidor ou ambos. Para utilizar do lado do servidor, você deve utilizar o evento ServerValidate. Você associa este evento ao controle da mesma forma com que faz outros eventos de outros controles. Os parâmetros de entrada da assinatura do evento é a mesma utilizada com a validação do lado do cliente. Os parâmetros source e args. Utilizando as mesmas propriedade para definir se a valiação foi válida ou não. O código a seguir, demonstra o mesmo exemplo utilizado anteriormente.


protected void NewPasswordCustomValidator_ServerValidate(object source, ServerValidateEventArgs args)
{
    string data = args.Value;
   
    // Start by setting false
    args.IsValid = false;
   
    // Check length
    if (data.Length < 6 || data.Length > 14) return;
   
    // Check for uppercase, lowercase, and numeric
    bool uc = false; bool lc = false; bool num = false;
    foreach (char c in data)
    {
        if (char.IsUpper(c))
        {
            uc = true;
        }
        else if (char.IsLower(c))
        {
        lc = true;
        }
        else if (char.IsNumber(c))
        {
        num = true;
        }
        if (uc && lc && num)
        {
            //must be valid
            args.IsValid = true;
            break;
        }
    }
}


Assim encerra esta primeira lição!!

segunda-feira, 15 de agosto de 2011

Capítulo 4: Using Server Controls Lição 2: Exploring Specialized Server Controls

Se olharmos a alguns anos atras, criar um simples calendário em uma página web era uma tarefa no minimo chata, era necessário criar tabelas, linhas e colunas, e adicinoar hyperlink nas datas, o javascript até poderia ajudar neste trabalho, mas ainda assim era uma tarefa chata.

O asp.net possui diversos controles onde o objetivo é justamente este facilitar no desenvolvimento de páginas que necessitam desses recursos. Esta lição irá falar sobre os seguinte controles que facilitam a nossa vida:
  • Table
  • Image
  • ImageButton
  • ImageMap
  • Calendar
  • FileUpload
  • Panel
  • MultiView
  • Wizard
  • Xml

The Table, TableRow, and TableCell Controls

Antigamente, e alguns desenvolvedores até hoje utilizam tables, tr e td html. Mas sabemos que devemos evitar o uso dessas tags html e usar divs, span e etc... Porém fica dificil fazer tudo com divs, quando se tem a necessidade de exibir dados tabulados.

Estes controles do asp.net tem o mesmo objetivo da table, tr e td do html, a grande diferença é que são Server Controls e por isso podem ser criados e manipulados em tempo execução.

O controle table possui uma propriedade que é uma coleção do controle TableRow, e por sua vez o TableRow possui uma propriedade que é uma coleção dos controles TableCell. Todos eles herdam a classe WebControl, por isso possuem as propriedades comuns como Font, BackColor e ForeColor.

Adding Rows and Cells Dynamically to a Table Control

O Visual Studio permite que você crie seu controle Table pelo designer dele, simplesmente arrastando o controle para sua página e editando suas propriedades, onde terá a opção de adicionar linhas e em seguida células. Porém se irá criar tabelas estáticas que não serão manipuladas em tempo de execução é recomendado que utilize as tabelas do html, pois terão melhor performance que os Controls Server do asp.net.

O único motivo para utilizar este controle é a necessidade de manipular em tempo de execução, a baixo código explicando:
  1. Na ToolBox arraste o Controle Table para sua página.
  2. Vá ao arquivo de code-behind e crie o evento PreInit do seu formulário.
  3. Dentro deste evento escreva um loop para criar 5 linhas em seu controle.
  4. Dentro deste loop, adicione outro loop para criar 3 célular dentro de cada linha.
  5. Dentro do último loop modifique a propriedade TableCell.Tex para identificar a linha e a coluna.
protected void Page_PreInit(object sender, EventArgs e)
{
  Table1.BorderWidth = 1;
  for (int row = 0; row < 5; row++)
   
  {
    TableRow tr = new TableRow();
     
    for (int column = 0; column < 3; column++)     
    {       
      TableCell tc = new TableCell();       
      tc.Text = string.Format("Row:{0} Cell:{1}", row, column); 
      tc.BorderWidth = 1; 
      tr.Cells.Add(tc);     
    } 
  Table1.Rows.Add(tr);   
  }
}


Neste código repare que foi modificado a propriedade Table1.BorderWidth e BorderWidth de cada célula também, o resultado será:

 

The Image Control

O controle de image como o nome ja sugere, renderiza uma imagem no browser, mais uma vez vale lembrar que só é válido usar este controle caso queira manipular em tempo de execução, caso contrário utilize a tag <img> do html. Aliás, o controle Image do asp.net irá renderizar uma <img> quando for processado.

O controle Image herda da classe WebControl e os controles ImageMap e ImageButton herdam diretamente de Image.

A propriedade primária do Image é ImageUrl que contém o caminho da imagem que será exibida no browser, mas existem mais algumas propriedades:
  • AlternateText: Esta propriedade tem diversas funções. Quando por algum motivo a imagem não for carregada no browser, o texto que irá aparecer no lugar dela é o que for definido nesta propriedade. A maioria dos navegadores exibe o texto desta propriedade quando passa o cursor do mouse por cima da imagem, como um Tooltip. E a função que considero mais importante é que ajuda usuário com necessidade especiais de acessibilidade para navegar em sua página. Caso sua imagem tenha um link utilize esta propriedade para descrever seu link, caso seja uma imagem de conteúdo descreva a imagem com palavras chaves para facilitar motores de busca a indexar sua imagem corretamente.
  • ImageAlign: Esta propriedade especifica a posição da imagem em relação a outros objetos em sua página. Existem as seguintes opções: NotSet, Left, Right, Baseline, Top, Middle, Bottom, AbsBottom, AbsMiddle, ou TextTop.
  • DescriptionUrl: Esta propriedade é outro recurso de acessibilidade, quando for usados leitores não visuais para acessar sua página, ele irá encontrar nesta propriedade um link, tem que ser uma url, que irá direcionar para uma página com texto explicativo ou audio, explicando melhor o que é aquela imagem.
  • GenerateEmptyAlternateText: Definindo esta propriedade para true, quando a página for carregada e por algum motivo a imagem não seja carregada a propriedade alt do objeto <img> ficará: alt="". Desta forma quando for usado um leitor não visual o software irá ignorar esta imagem, entendo que ela não tem significado para a página.
A baixo um exemplo de código de como criar um controle Image em tempo de execução:
protected void Page_Load(object sender, EventArgs e)
{
  Image1.ImageUrl = "~/images/whale.jpg";
  Image1.DescriptionUrl = "~/WhaleImageDescription.htm";
  Image1.AlternateText = "This is a picture of a whale";
}


The ImageButton Control


O controle de Image não possui o evento click, se você necessitar deste evento, é necessário utilizar o controle ImageButton ou ImageMap, estes controles são renderizados como o controle Image com a diferença de funcionar como um botão, com estes controles é possível também localizar as coordenadas x e y de onde o usuário clicou, caso queira tomar alguma decisão em relação a este aspecto.


O controle ImageButton é renderizado no html como: <input type="image">, por ter eventos associados a ele, é possível executar um PostBack em seu formulário através do controle. Por herdar diretamente do controle Image o ImageButton possui as mesmas propriedades como AlternateText, DescriptionUrl, ImageAlign, e GenerateEmptyAlternateText.


O ImageButton assim como o Button possui dois eventos o click e o command, a diferença entre eles já explique em lições anteriores. O segundo parâmetro de ambos os eventos é do tipo ImageClickEventArgs, que é o parâmetro que possui as coordenadas do clique.


O código a seguir demonstra o clique em um ImageButton:


public partial class ImageButton_Control : System.Web.UI.Page
{
  protected void Page_Load(object sender, EventArgs e)
  {
    ImageButton1.ImageUrl = "~/images/redblue.jpg";
    ImageButton1.AlternateText =
        "This is a button. The left side is red. The right is blue.";
  }
  protected void ImageButton1_Click(object sender, ImageClickEventArgs e)
  {
    ImageButton1.AlternateText =
        string.Format("Button Clicked at {0},{1}", e.X, e.Y);
  }
}



Repare que no evento Click do botão, é definida a propriedade AlternateText com os valores das coordenadas de onde o usuário clicou.


The ImageMap Control

O ImageMap é similar ao ImageButton, a grande diferença é que em qualquer lugar que clicar do ImageButton irá ocasionar o PostBack, já com o ImageMap é possível definir regiões "hot spots" que irão ocasionar o PostBack.

O ImageMap quando renderizado gera o elemento html: <img usemap="#myMap">. Assim como o ImageButton o ImageMap herda diretamente da classe Image, por isso possui as mesmas propriedades.


No asp.net o ImageMap é representado pelo elemento: <asp:ImageMap> e seus elementos são: CircleHotSpot, RectangleHotSpot, e PolygonHotSpot.

Working with HotSpot Classes

O HotSpot é uma área pré-definida da imagem que quando clicada irá executar uma ação. É possível criar várias áreas dentro da mesma imagem. As classes que herdam da classe HotSpot são CircleHotSpot, RectangleHotSpot, e PolygonHotSpot. Propriedades:
  • AccessKey: já explicado anteriormente em outros controles;
  • AlternateText: já explicado anteriormente em outros controles;
  • HotSpotMode: Comportamento quando clicar na área (HotSpot) criada. Pode ser definido como: NotSet, Inactive, Navigate, ou PostBack;
  • NavigateUrl: Url que irá navegar quando a área for clicada;
  • PostBackValue: Uma string que será passada para o lado do servidor quando a área for clicada;
  • TabIndex: Número indice do HotSpot;
  • Target: A janela ou frame que será exibido o resultado do clique da área.
 Understanding the HotSpotMode Property
A propriedade HotSpotMode é usada para definir o comportamento do HotSpot quando ele for clicado. Esta propriedade pode ser definida tanto em um HotSpot como no controle ImageMap. Se você definir o valor desta propriedade para ambos, prevalecerá o valor que estiver no HotSpot e ignorará o valor atribuido ao ImageMap. Vamos aos valores permitidos desta propriedade:
  •  NoSet: É usado quando você quer herdar o comportamento padrão definido no controle ImageMap, você define a propriedade no ImageMap e no HotSpot deixe como NotSet;
  • Navigate: Simples, especifique uma url que será aberta quando clicar em seu HotSpot;
  • PostBack: Quando o HotSpot for clicado ele irá executar um PostBack em seu formulário enviando os dados para o servidor. Basta criar o evento e informar o valor da propriedade PostBackValue que será passada no parâmetro ImageMapEventArgs do seu evento.
  • Inactive: Como o nome já diz não será feito nada. Por que usar? Você pode criar HotSpot de zonas complexas, onde você define uma área inativa dentro de outro HotSpot ativo.
O código abaixo demonstra como usar, teremos uma imagem que contém 3 cores e é possível definir a região de cada cor:
public partial class HotSpotControl : System.Web.UI.Page
{
  protected void Page_Load(object sender, EventArgs e)
  {
    ImageMapStopLight.ImageUrl = "~/images/stoplight.jpg";
 
    ImageMapStopLight.AlternateText = "Stoplight picture"; 
    ImageMapStopLight.HotSpotMode = HotSpotMode.PostBack;     
    RectangleHotSpot redHotSpot = new RectangleHotSpot();     
    redHotSpot.Top = 0;     
    redHotSpot.Bottom = 40;    
     redHotSpot.Left = 0;     
    redHotSpot.Right = 40;     
    redHotSpot.PostBackValue = "RED";    
     ImageMapStopLight.HotSpots.Add(redHotSpot);    
     RectangleHotSpot yellowHotSpot = new RectangleHotSpot();    
     yellowHotSpot.Top = 41;        
    yellowHotSpot.Bottom = 80;     
    yellowHotSpot.Left = 0;     
    yellowHotSpot.Right = 40;     
    yellowHotSpot.PostBackValue = "YELLOW"; 
    ImageMapStopLight.HotSpots.Add(yellowHotSpot);    
    RectangleHotSpot greenHotSpot = new RectangleHotSpot();    
    greenHotSpot.Top = 81;
    greenHotSpot.Bottom = 120;     
    greenHotSpot.Left = 0;     
    greenHotSpot.Right = 40;     
    greenHotSpot.PostBackValue = "GREEN";     
    ImageMapStopLight.HotSpots.Add(greenHotSpot);   
  }
  protected void ImageMapStopLight_Click(object sender, ImageMapEventArgs e)
  {

    Label1.Text = string.Format("You clicked the {0} rectangle.", e.PostBackValue);
  }
}
Resultado quando se clica no retângula verde:

The Calendar Control

O controle Calendar irá exibir um calendário em sua página. Ele é usado para seleção de datas, seja um única data ou um conjunto de datas. No asp.net o elemento dele é o <asp:Calendar>, quando renderizado em sua página ele irá gerar uma <table> html associada com javascripts que o próprio asp.net irá criar.


Como eu disse o Calendar tem a opção de selecionar nenhum ou várias datas, isto é contralado pela propriedade SelectionMode, e as opções disponíveis são:
  • Day: permite selecionar uma data simples;
  • Week: permite selecionar uma data simples ou uma semana completa;
  • WeekMonth: permite selecionar uma data simples, uma semana completa ou todo o mês;
  • one: não permite que você selecionar qualquer data.
O Calendar tem uma série de propriedades que permite você ajustar seu formato:
  • Caption: texto renderizado no calendário;
  • CaptionAlign: alinhamento do texto: Top, Bottom, Left, Right, ou NotSet;
  • CellPadding: espaço da célula para a borda da célula;
  • CellSpacing: espaço entra cada célula;
  • DayHeaderStyle: o estilo que será aplicado aos dias da semana;
  • DayNameFormat: o formato dos nomes dos dias das semanas: FirstLetter,
    FirstTwoLetters, Full, Short, Shortest;
  • DayStyle: estilo padrão para os dias do calendário;
  • FirstDayOfWeek: o dia da semana que será exibido na primeira coluna do calendário;
  • NextMonthText: texto que será exibido no controle de navegação para ir para o próximo mês, por padrão o usado é >. Este controle de navegação só é habilitado quando a propriedade ShowNextPrevMonth for true;
  • NextPrevFormat: define o formato dos controles de navegação próximo e anterior. Pode ser definido como CustomText (padrão), FullMonth(exemplo Janeiro) ou ShortMonth (exemplo Jan);
  • NextPrevStyle: estilo que será aplicado aos controles de navegação;
  • OtherMonthDayStyle: estilo dos dias do calendário e não são do mês selecionado;
  • PrevMonthText: texto que será exibido no controle de navegação para ir para o mês anterior, por padrão o usado é <. Este controle de navegação só é habilitado quando a propriedade ShowNextPrevMonth for true;
  • SelectedDate: data selecionada pelo usuário;
  • SelectedDates: coleção de datas selecionada pelo usuário, quando assim for permitido;
  • SelectedDayStyle: estilo da data selecionada;
  • SelectionMode: valor que indica como as datas podem ser selecionadas, como ja expliquei a cima;
  • SelectMonthText: texto exibido para a seleção do mês, por padrão é >>;
  • SelectorStyle: estilo para os seletores de semana e mês;
  • SelectWeekText: texto de seleção da semana no seletor;
  • ShowDayHeader: indica se o header do dia deve ser exibido;
  • ShowGridLines: indica se deve exibir gridLines;
  • ShowNextPrevMonth: indica se os controles de navegação entre meses deve ser exibido;
  • ShowTitle: indica se o titulo deve ser exibido;
  • TitleFormat: indica como deve ser o formato do título, exibindo o mês ou mês e ano;
  • TitleStyle: estilo do título;
  • TodayDayStyle: estilo do dia atual;
  • TodaysDate: data de hoje;
  • UseAccessibleHeader: quando definido como true os headers do dia serão gerados como <th>, é o padrão, quando definido como false serão gerados <td>;
  • VisibleDate: define qual data será exibida quando o calendário for exibido;
  • WeekendDayStyle: estilo dos dias de final de semana.
O Calendar também possui eventos para se trabalhar. O evento primário é o SelectionChanged, ele causa um potback e é disparado no momento em que o usuário seleciona uma nova data no calendário. Dentro desta evento é possivel receber a data selecionada através da propriedade SelectedDate.
Outro evento é o VisibleMonthChanged que também causa um postback e é disparado no momento em que o usuário altera o mês que esta visivel no calendário.

O calendar é tipicamente usado como um selecionador de datas, mas pode ser usado para exibir tarefas agendadas.Utilizando o evento DayRender, que é disparado no momento em que o calendário esta sendo criado e irá ser renderizado no html a cada dia do mês, você pode adicionar controles como um label junto com o dia do calendário.

O código abaixo demonstra como exibir as informações em texto de datas especiais junto com o dia no calendário.

private Dictionary<DateTime, string> scheduleData = new Dictionary<DateTime,string>(5);

protected void Page_Load(object sender, EventArgs e)
{
  // Load the schedule (which would be read from a database)
   
  scheduleData.Add(new DateTime(2011, 1, 9), "Vacation Day");  
  scheduleData.Add(new DateTime(2011, 1, 18), "Budget planning meeting");  
  scheduleData.Add(new DateTime(2011, 2, 5), "Conference call");   
  scheduleData.Add(new DateTime(2011, 2, 10), "Meet with art director");   
  scheduleData.Add(new DateTime(2011, 2, 15), "Vacation day");   
  Calendar1.Caption = "Personal Schedule";
  Calendar1.FirstDayOfWeek = FirstDayOfWeek.Sunday;  
   Calendar1.NextPrevFormat = NextPrevFormat.ShortMonth;  
   Calendar1.TitleFormat = TitleFormat.MonthYear;   
  Calendar1.ShowGridLines = true;  
  Calendar1.DayStyle.HorizontalAlign = HorizontalAlign.Left;   
  Calendar1.DayStyle.VerticalAlign = VerticalAlign.Top;   
  Calendar1.DayStyle.Height = new Unit(75);   
  Calendar1.DayStyle.Width = new Unit(100);   
  Calendar1.OtherMonthDayStyle.BackColor = System.Drawing.Color.Cornsilk; 
  Calendar1.TodaysDate = new DateTime(2011, 1, 1);   
  Calendar1.VisibleDate = Calendar1.TodaysDate;
}


protected void Calendar1_SelectionChanged(object sender, EventArgs e)
{
  
  ActionLabel.Text = string.Format("Selection changed to: {0}", Calendar1.SelectedDate.ToShortDateString());
}


protected void Calendar1_VisibleMonthChanged(object sender, MonthChangedEventArgs e)
{
 
  ActionLabel.Text = string.Format("Month changed to: {0}", e.NewDate.ToShortDateString());
}


protected void Calendar1_DayRender(object sender, DayRenderEventArgs e)
{
  
  if (scheduleData.ContainsKey(e.Day.Date))   
  {     
    Literal lit = new Literal();     
    lit.Text = "<br />";     
    e.Cell.Controls.Add(lit);    
    Label lbl = new Label();     
    lbl.Text = (string)scheduleData[e.Day.Date];     
    lbl.Font.Size = new FontUnit(FontSize.Small);     
    e.Cell.Controls.Add(lbl);   
  }
}

Este código define no evento Page_Load algumas propriedades do calendário, e utiliza o evento Calendar1_DayRender para fazer a verificação se a data é uma data especiail para ser exibida. Veja o resultado:


The FileUpload Control

O controle FileUpload permite ao usuário fazer o upload de arquivos para o servidor. Este controle exibe um textbox e um botão. O usuário pode informar o caminho completo do arquivo ou clicar no botão e navegar pelo browser até encontrar o arquivo desejado.

Sua tag no asp.net é <asp:FileUpload> quando renderizado no html ele gera um <input type="file">

O FileUpload não ocasiona postback de forma automática, somente é feito o postback por intervenção de outro controle como um botão de enviar/gravar ou outro.

As propriedade para acessar o arquivo são:
  • FileBytes: Expõe o arquivo como um array de byte;
  • FileContent: Expõe o arquivo como stream;
  • PostedFile: Expõe o arquivo como objeto do tipo HttpPostedFile. Este objeto contém outras propriedades como ContentType e ContentLength.
É importante que você fala uma análisa do arquivo que esta sendo enviado para o servidor. Você pode analisar características como nome do arquivo, tamanho e tipo. Quando estiver tudo ok, utiliza o método SaveAs para completar o upload.

O tamanho máximo do arquivo que pode ser utilizado é configurado pelo atributo MaxRequestLength que fica no elemento httpRuntime no arquivo web.config. Se o usuário tentar postar algo maior do que o delimitado o upload irá falhar. 

No exemplo a baixo foi criado uma página com um FileUpload e um botão para salvar o arquivo em uma pasta chamada Uploads:

protected void Button1_Click(object sender, EventArgs e)
{
  if (FileUpload1.HasFile)
  {
    Label1.Text = string.Format("File Length: {0}<br />File Name: {1}<br />MIME Type: {2}",     

    FileUpload1.FileBytes.Length, FileUpload1.FileName, FileUpload1.PostedFile.ContentType);
    FileUpload1.SaveAs(MapPath("~/Uploads/" + FileUpload1.FileName));
  }
  else
  {
    Label1.Text = "No file received.";
  }
}



Como resultado, após clicar no botão submit o arquivo será salva na pasta destino e exibirá suas popriedades na label:



The Panel Control

O Panel é usado como um container. Ele é útil quando você precisar agrupar um grupo de controles. O exemplo mais comum é colocar vários controles dentro dele e conseguir esconder e exibir todos alterando somente a propriedade visible do Panel.

No asp.net sua tag é <asp:Panel> quando renderizado no html será gerado uma <div>. Algumas propriedades do Panel:
  • BackImageUrl: Usado para exibir uma imagem de fundo no Panel;
  • HorizontalAlignment: Define o alinhamento horizontal dos controles que estão dentro do Panel;
  • Wrap: Especifica se os controles que estão dentro do Panel continuam na próxima linha quando acabar o espaço da linha.
  • DefaultButton: Especifica o botão que será disparado quando o focu estiver no Panel e o usuário pressionar a tecla Enter.
No exemplo a seguir com o clique do botão o usuário consegue esconder um grupo de controles que estão dentro do Panel:

Código aspx:
<body>
<form id="form1" runat="server">
<div>
<asp:Button ID="ButtonShowHide" runat="server" Text="Login: hide form"
width="200" onclick="ButtonShowHide_Click"/>
<asp:Panel ID="Panel1" runat="server" BackColor="Beige" Width="200">
<asp:Label ID="Label1" runat="server" Text="User name: "></asp:Label>
<br />
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<br />
<asp:Label ID="Label2" runat="server" Text="Password: "></asp:Label>
<br />
<asp:TextBox ID="TextBox2" runat="server"></asp:TextBox>
<br />
<asp:Button ID="ButtonLogin" runat="server" Text="Login" />
</asp:Panel>
</div>
</form>
</body>



Código c#:
protected void ButtonShowHide_Click(object sender, EventArgs e)
{
  Panel1.Visible = !Panel1.Visible;
  if (Panel1.Visible)
  {
    ButtonShowHide.Text = "Login: hide form";
  }
  else
  {
    ButtonShowHide.Text = "Login: show form";
  }
}


Neste exemplo clicando no botão o usuário ira alterar em esconder e exibir os controles de login.


The MultiView and View Controls


Assim como o Panel, os controles de MultiView e View trabalham como container para agrupar controles. A MultiView funciona como container da View, que por sua vez é o container dos demais controles. Dentro de uma MultiView podem contar várias Views. Esses controles foram criados para trabalhar juntos e não podem ser usados separadamente.

Você deve usar a propriedade ActiveViewIndex ou o método SetActiveView para definir qual View é exibida. Se o ActiveViewIndex for definido como -1, nenhum controle de View será exibido, se for passada uma View inválida ou null para o método SetActiveView uma exception será disparada. Repare que somente uma View pode estar ativa por vez.

Um exemplo útil do uso desses controles é a criação de wizards, onde por exemplo um usuário deve seguir de 3 a 4 passos para se registrar em um site. Cada passo desse registro pode estar em uma View diferente, veja na imagem:


Para gerenciar esta página foram criados command buttons para navegação. Quando o usuário clicar no botão através da propriedade CommandName do CommandEventArgs será possível identificar no evento qual botão foi clicado. Veja o código:

public partial class ViewControl : System.Web.UI.Page
{
  protected void Page_Load(object sender, EventArgs e)
  {
    MultiView1.ActiveViewIndex = 0;
  }

  protected void Button_Command(object sender, CommandEventArgs e)
  {
    switch (e.CommandName)
    {
      case "Step1Next":
        MultiView1.ActiveViewIndex = 1;
        break;
      case "Step2Back":
        MultiView1.ActiveViewIndex = 0;
        break;
      case "Step2Next":
        MultiView1.ActiveViewIndex = 2;
        break;
      case "Step3Back":
        MultiView1.ActiveViewIndex = 1;
        break;
      case "Finish":
        //hide control from user to simulate save
        MultiView1.ActiveViewIndex = -1;
        break;
    }
  }
}


Quando a página for exibida sera mostrada a primeira View para o usuário como o primeiro passo, e conforme ele for navegando as demais Views vão sendo exibidas e outras escondidas:


The Wizard Control

O controle Wizard é um controle complexo que agrega controles para que o usuário possa de forma continua inserir informações em sua webpage. O Wizard funciona de forma semelhante aos controles de MultiView e View explicados anteriormente. A idéia dele é criar um passo a passo lógico de um processo.

O que é feito com o Wizard pode muito bem ser feito com várias páginas, mas esta é a diferença principal, com o Wizard você centraliza tudo em uma unica página, facilitando o processo de desenvolvimento.

O Wizard possui um header para customizar com informações do passo especifico que o usuário esta naquele momento. Possui uma sidebar que irá conter os controles de navegação entre cada passa do Wizard. É possível programar qual passo é exibido, não obrigando o usuário a passar em todos os passos de forma linear caso não queira.


O que determina qual botão é exibido ou não é a propriedade StepType da classe BaseWizardStep. Os valores disponíveis são:
  • WizardStepType.Auto: este é o valor padrão. Os botões são renderizados com base na localização do passo dentro da coleção do Wizard;
  • WizardStepType.Complete: este é o passo final da coleção de passos, os botões de Final e Anterior serão exibidos;
  • WizardStepType.Start: este é o primeiro passo, e somente o botão de próximo irá aparecer;
  • WizardStepType.Step: este é um passo intermediário, os botões de Próximo e Anterior são renderizados.
No exemplo a seguir o controle de Wizard é montado para dar opção do usuário escolher alguns itens do seu veículo. Os passos criados no Wizard são: Exterior, Interior, Opcionais, and Resumo. No Exterior contem 3 RadioButtons para escolher a cor externa: vermelho, azul ou preto. No passo do Interior contém 2 RadioButton para escolher se quer banco de couro ou de pano. Nos Opcionais contém CheckBox para escolher: Rádio, Bancos Aquecidos e Ar-Condicionado. No Resumo tem uma Label que é populada com as opções escolhidas. Veja como ficou:




Após cada passo do Wizard ser criado, foi criado um código para popular a Label quando chegar ao Resumo, também foi adicionado código no evento Page_Load da página para determinar o primeiro passo do Wizard. E no evento Wizard1_FinishButtonClick foi adicionado código para exibir os resultados na label.


protected void Page_Load(object sender, EventArgs e)
{
  if (!IsPostBack)
  {
    Wizard1.ActiveStepIndex = 0;
  }
}
 

protected void Wizard1_FinishButtonClick(object sender, WizardNavigationEventArgs e)
{
  Wizard1.Visible = false;
  Response.Write(string.Format("Finished<br />{0}", Label1.Text));
}


protected void Wizard1_NextButtonClick(object sender, WizardNavigationEventArgs e)
{
  if (Wizard1.WizardSteps[e.NextStepIndex].Title == "Summary")
  {
    StringBuilder sb = new StringBuilder();
    foreach (WizardStep ws in Wizard1.WizardSteps)
    {
      foreach (Control c in ws.Controls)
      {
        if (c is CheckBox)
        {
          CheckBox cb = (CheckBox)c;
          if (cb.Checked)
          {
            sb.AppendFormat("{0}<br />", cb.Text);
          }
        }
      }
    }
    Label1.Text = sb.ToString();
  }
}



Quando a página for exibida, o primeiro passo será exibido ao usuário (Exterior), o usuário pode ir passo a passo ou ir direto para o passo final clicando em Finish. Quando clicar no Finish o controle de Wizard será escondido e irá aparecer o Resumo onde a Label é populada com as opções escolhidas.

The Xml Control 

O controle Xml é utilizado para exibir o conteúdo de arquivos Xml. Este controle é bastante útil quando seus dados estão armazenados em arquivo Xml e você precisa executar uma transformação para Extensible Stylesheet Language (XSL). Os dados podem ser renderizados e exibidos para o usuário utilizando o controle Xml.

O documento Xml será exibido se especificada a propriedade DocumentSource ou a propriedade DocumentContent. A propriedade DocumentSource aceita uma string que contém o caminho do arquivo Xml a ser carregado. A propriedade DocumentContent aceita uma string com o conteúdo do Xml.

A propriedade TransformSource aceita um parâmetro opcional que contém o caminho de um arquivo XSL que será aplicado ao Xml. Esta propriedade também aceita um objeto do tipo Transform. O controle Xml contém a propriedade TransformArgumentList que aceita parâmetros que serão passados para a transformação XSL.


No código a seguir o controle Xml é utilizado para exibid o contéudo de um arquivo Xml após uma transformação XSL é aplicada. A seguir o arquivo Xml e o arquivo XSL:


Arquivo XML: ProductList.xml
<?xml version="1.0" encoding="utf-8" ?>
<ProductList>
<Product Id="1A59B" Department="Sporting Goods" Name="Baseball" Price="3.00" />
<Product Id="9B25T" Department="Sporting Goods" Name="Tennis Racket" Price="40.00" />
<Product Id="3H13R" Department="Sporting Goods" Name="Golf Clubs" Price="179.00" />
<Product Id="7D67A" Department="Clothing" Name="Shirt" Price="12.00" />
<Product Id="4T21N" Department="Clothing" Name="Jacket" Price="45.00" />
</ProductList>



Arquivo XSL: ProductList.xsl
<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:labs="http://labs.com/mynamespace">
<xsl:template match="/">
<html>
<head>
<title>Product List</title>
</head>
<body>
<center>
<h1>Product List</h1>
<xsl:call-template name="CreateHeading"/>
</center>

</body>
</html>
</xsl:template>
<xsl:template name="CreateHeading">
<table border="1" cellpadding="5">
<tr >
<th bgcolor="yellow">
<font size="4" >
<b>Id</b>
</font>
</th>
<th bgcolor="yellow">
<font size="4" >
<b>Department</b>
</font>
</th>
<th bgcolor="yellow">
<font size="4" >
<b>Name</b>
</font>
</th>
<th bgcolor="yellow">
<font size="4" >
<b>Price</b>
</font>
</th>
</tr>
<xsl:call-template name="CreateTable"/>
</table>
</xsl:template>
<xsl:template name="CreateTable">
<xsl:for-each select="/ProductList/Product">
<tr>
<td align="center">
<xsl:value-of select="@Id"/>
</td>
<td align="center">
<xsl:value-of select="@Department"/>
</td>
<td>
<xsl:value-of select="@Name"/>
</td>
<td align="right">
<xsl:value-of select="format-number(@Price,'$#,##0.00')"/>
</td>
</tr>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>



Para exibir o resultado foi adicionado um controle Xml na página e o código a seguir:


public partial class XmlControlVb : System.Web.UI.Page
{
  protected void Page_Load(object sender, EventArgs e)
  {
    Xml1.DocumentSource = "~/App_Data/ProductList.xml";
    Xml1.TransformSource = "~/App_Data/ProductList.xsl";
  }
}



Quando a página é exibida os arquivos são carregados e o resultado:




Com o controle Xml encerra o capítulo 4!!