Apaixonado por tecnologia. Trabalho com tecnologia desde 2003.

Saiba mais sobre minha vida profissional aqui .

Fale comigo.
Siga-me no Twitter
Ultimos comentários
Calendário de Posts
<<  julho 2017  >>
stqqssd
262728293012
3456789
10111213141516
17181920212223
24252627282930
31123456

Siga o @DicaDoNerd no Twitter e acompanhe as novidades


Que Jquery é uma bibliocate que facilita muito a vida do programador, isso ninguém duvida, mas, uma coisa que as vezes temos problemas e entender os plugins que são criados. Quando entendemos colocamos a mão na cabeça e dizemos “Como sou burro, era só isso!”… Sempre que tenho um problema que não consigo resolver a primeira coisa é pesquisar no Google mas como não gosto simplesmente do “Copy and Paste”, fico tentando entender bibliotecas, refatorando dll’s, estudando alguns frameworks, então, lá vai mais uma dica.

Vou utilizar neste exemplo o plugin masked input.

Existe uma forma bem simples de criar, basta criar um estilo (css) para seu Input (asp:TextBox)

.campoFormData {font-family: Arial, Helvetica, sans-serif;font-size: 12px;font-weight: normal;color: #FFFFFF;text-decoration: none;background-color: #666666;border: 0px solid #666666;}
.campoFormCEP {font-family: Arial, Helvetica, sans-serif;font-size: 12px;font-weight: normal;color: #FFFFFF;text-decoration: none;background-color: #666666;border: 0px solid #666666;}
.campoFormTel {font-family: Arial, Helvetica, sans-serif;font-size: 12px;font-weight: normal;color: #FFFFFF;text-decoration: none;background-color: #666666;border: 0px solid #666666;}
.campoFormDDD {font-family: Arial, Helvetica, sans-serif;font-size: 12px;font-weight: normal;color: #FFFFFF;text-decoration: none;background-color: #666666;border: 0px solid #666666;}
.campoFormCPF {font-family: Arial, Helvetica, sans-serif;font-size: 12px;font-weight: normal;color: #FFFFFF;text-decoration: none;background-color: #666666;border: 0px solid #666666;}
.campoFormCNPJ {font-family: Arial, Helvetica, sans-serif;font-size: 12px;font-weight: normal;color: #FFFFFF;text-decoration: none;background-color: #666666;border: 0px solid #666666;}
.campoFormD2 {font-family: Arial, Helvetica, sans-serif;font-size: 12px;font-weight: normal;color: #FFFFFF;text-decoration: none;background-color: #666666;border: 0px solid #666666;}

Criamos classes para cada Tipo de formatação (vale lembrar que isso será utilizado no Selector ($) do Jquery).

Feito isso, vamos para o HTML.

<asp:TextBox ID="txtCPF" runat="server" MaxLength="15" CssClass="campoFormCPF"  />
<asp:TextBox ID="txtCEP" runat="server" CssClass="campoFormCEP" MaxLength="9" />
<asp:TextBox ID="txtTelefone" runat="server" MaxLength="10" CssClass="campoFormTel" />
<asp:TextBox ID="txtCelularDDD" runat="server" MaxLength="2" CssClass="campoFormDDD" Width="20px" />
<asp:TextBox ID="txtCelular" runat="server" MaxLength="10" CssClass="campoFormTel" />

Agora vamos referenciar a biblioteca do Jquery.

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script src="http://cloud.github.com/downloads/digitalBush/jquery.maskedinput/jquery.maskedinput-1.3.min.js">
</script>

Apenas lembrando para quem utiliza o Visual Studio 2010 (Framework 4.0) é possível habilitar a biblioteca do Jquery (sem precisar fazer a referência do script) habilitando a propriedade EnableCdn (Content Delivery Network). Neste link você encontra algumas dicas bem bacanas sobre algumas novidades e aqui você encontra as bibliotecas disponíveis no Cdn.

<asp:ScriptManager ID="smMaster" runat="server" EnablePartialRendering="true" EnableCdn="true" />

Agora vamos criar o script que será responsável por executar o script.

function AtribuirMascaras() {

$(".campoFormD2").unmask();
$(".campoFormD2").mask("99");

$(".campoFormData").unmask();
$(".campoFormData").mask("99/99/9999");

$(".campoFormCEP").unmask();
$(".campoFormCEP").mask("99999-999");

$(".campoFormTel").unmask();
$(".campoFormTel").mask("9999-9999");

$(".campoFormDDD").unmask();
$(".campoFormDDD").mask("99");

$(".campoFormCPF").unmask();
$(".campoFormCPF").mask("999.999.999-99");

$(".campoFormCNPJ").unmask();
$(".campoFormCNPJ").mask("99.999.999/9999-99");

}

Com a função pronta, vamos executar:

<script type="text/javascript">
$(document).ready(function () {
AtribuirMascaras();
});
</script>

Um problema comum para quem utiliza este plugin (Mask) com UpdatePanel é ele se “perder” isso acontece, pelo fato de que foi enviada uma requisição para o servidor e o HTML retornado não tem mais o evento vinculado aos controles.

Postei há algum tempo uma forma bem simples de resolver este problema, basta fazer isso:

<script>
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(registraScript);

function registraScript(sender, args) {
AtribuirMascaras();
}


</script>

Isso faz com que ao final de cada requisição ao servidor o script seja registrado novamente.

Um constante problema ao utilizar algum script de qualquer Framework (Jquery, ExtJs) e colocarmos dentro de um UpdatePanel do ASP.NET o script simplesmente para de funcionar. Isso acontece pelo fato de como uma transação assíncrona ocorrida dentro do UpdatePanel transita apenas o pedaço de código para o servidor.

Existe uma forma bem simples de resolver este problema. Toda vez que é feita uma requisição o Script Mananger controla eventos como Inicio da Requisição (beginRequest), Carregamento do Página (PageLoad) e finalização da requisição (endRequest).

Basta “chamar” o script novamente que o problema estará resolvido. Isso acontece também, quando utilizado apenas um ScriptMananger na Master Page, você pode escolher se deseja controlar a requisição na Master Page ou se deseja controlar em Páginas (ASPX) separadamente.

Vamos lá!

<script>
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(registraScript);

function registraScript(sender, args) {
//Execute aqui seu script.
}


</script>


Resolvi escrever este post, pois, no analytics notei que muitas pessoas que chegam até o meu blog, estão com perguntas como: Update Panel + Jquery ou MasterPage Jquery…. estas são as campeãs de solicitação.

 

Não encontrou o que procurava?  Entre em contato. ;-)

Normalmente sou desconfiado de soluções de auto-complete. Vou realizar um próximo post, que mostra como fazer a mesma coisa utilizando JQuery. Porém a solução do Jquery exige que você coloque todas as informações da consulta no formato Json no momento em que carrega a página, isso pode ser eficiente para poucos registros, para grande quantidades de registros, acredito que o Auto Complete do Ajax Control Toolkit seja mais indicado.

image
Imagem 1

Vou utilizar Linq To Sql para a implementação deste exemplo, pois acredito que é um dos frameworks que trazem maior produtividade em desenvolvimento. Estou utilizando dados e exemplos de um projeto real que está em produção, por isso, os nomes não sejam conhecidos como o Northwind ou Pubs.

Bom, vamos primeiro entender a estrutura.

Criei uma entidade (utilizando o LinToSql). (Imagem 1), assim, teremos acesso aos dados e podemos criar os métodos para acessos aos dados utilizando o mapeamento relacional gerado automaticamente.

Vamos agora criar o método que será utilizado pelo webservice que é necessário para utilização do auto-complete.

using System;
using System.Linq;

namespace PitStop.Dados
{
public class CadastroCliente : IDisposable
{
//Crio a variavel que irá conter o contexto dos Dados.
private dbDataContext dbContext;

/// <summary>
/// Construtor da classe.
/// </summary>
public CadastroCliente()
{
//No construtor, crio a instancia do contexto.
dbContext = new dbDataContext();
}

/// <summary>
/// Retorna clientes que possam atender a consulta
/// </summary>
/// <param name="textoBuscar">Parte do nome do cliente</param>
/// <param name="count">Quantidade de itens que serão retornados</param>
/// <returns>array com nome dos clientes</returns>
public string[] RetornarNomesClientes(string textoBuscar, int count)
{
//Aqui é um pulo do gato, como vamos apenas fazer a consulta, desabilitamos o tracking que por padrão fica habilitado.
//Funciona apenas para consulta, qualquer ação que necessite que o estado seja salvo (Update, Insert, Delete) é necessário habilitar.
dbContext.ObjectTrackingEnabled = false;

return dbContext.ClienteEntidades
.Where(p => p.Inativo == false && p.Nome.ToLower().Contains(textoBuscar)) // Filtro clientes ativos e que contenham o texto.
.Select(m => m.Nome) // não há necessidade da entidade inteira, então, retorno apenas o nome
.Take(count) // retorno apenas a quantidade quantidade necessária
.ToArray(); // Converto o resultado para um array.
}


// Fecho o que pode estar aberto.
#region IDisposable Members

~CadastroCliente()
{
this.Dispose();
}

public void Dispose()
{
GC.Collect();
GC.SuppressFinalize(this);
}

#endregion
}
}

Agora, vamos criar o WebService que será chamado pelo componente do AutoCompleteExtender. Clique com o Botão direito e selecione o item “WebService”.

image

Ao adicionar o WebService, vamos criar o método responsável por invocar o método que criamos nos passos anteriores.

using System.Web.Services;
using PitStop.Dados;

namespace PitStop.Web.webService
{
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
[System.Web.Script.Services.ScriptService]
public class AutoComplete : System.Web.Services.WebService
{
public AutoComplete()
{
}

/// <summary>
/// Retorna dados para o autoComplete
/// </summary>
/// <param name="prefixtext">Texto que será pesquisado</param>
/// <param name="count">Quantidade de registros que serão retornados</param>
/// <returns>array com nome dos clientes</returns>
[WebMethod]
public string[]RetornarClientes(string prefixtext, int count)
{
using (CadastroCliente cad = new CadastroCliente())
{
return cad.RetornarNomesClientes(prefixtext, count);
}

}
}

}

Pronto, estrutura pronta agora vamos preparar a interface, que consumirá a informação

Em uma nova página aspx:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="TesteComplete.aspx.cs" Inherits="PitStop.Web.TesteComplete" %>
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="asp" %>

<!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 runat="server">
<title>Teste Auto Complete</title>
<style type="text/css">
.autocomplete_list {visibility:visible;margin:0px!important;padding:1px;background-color:GrayText;color:Black;
border:buttonshadow;border-width:1px;border-style:solid;cursor:default;text-align:left;list-style-type:none;
font-weight:normal;font-family:Verdana;font-size:10px;}
.autocomplete_highlighted_listitem {background-color: GrayText;color:Black;padding:3px;}
.autocomplete_listitem {background-color:Window;color:Gray;font-family: Verdana;font-size: 10px;padding:3px;}

</style>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ToolkitScriptManager ID="sm" runat="server" />
<asp:AutoCompleteExtender ID="ace" runat="server"
EnableCaching="true"
MinimumPrefixLength="1"
TargetControlID="txtNome"
ServicePath="~/webService/AutoComplete.asmx"
ServiceMethod="RetornarClientes"
CompletionInterval="10"
CompletionSetCount="10"
CompletionListCssClass="autocomplete_list"
CompletionListItemCssClass="autocomplete_listitem"
CompletionListHighlightedItemCssClass="autocomplete_highlighted_listitem">

</asp:AutoCompleteExtender>
<asp:TextBox ID="txtNome" runat="server" CssClass="campoForm" Width="400px" autocomplete="off" />

</div>
</form>
</body>
</html>

Vale algumas dicas:

CompletionSetCount = 10 –> Indica a quantidade de registros que serão exibidos na lista do auto-complete.

EnableCaching = true –> Guarda as ultimas consultas realizadas.

MinimumPrefixLength = 1 –> Indica a partir de quantos caracteres digitados será realizado o auto-complete (o ideal seria 3 a 5)

CompletionListCssClass, CompletionListItemCssClass e CompletionListHighlightedItemCssClass você consegue alterar o estilo (css) do auto-complete.

Uma coisa legal é autocomplete="off" que utilizei no TextBox (txtNome) isso indica que não será utilizado o autocomplete do browser, pois, isso pode confundir o usuário.

Vamos ver o resultado?

image

Espero que tenham gostado... Dúvidas ou sugestões de artigos entrem em contato ;-).

Até a próxima.

     Neste artigo vou demonstrar uma forma muito simples de criar uma TreeView, funcional com manutenção simples e com um estilo legal. Para criar esta TreeView utilizei LinqToSql que facilita muito a vida de qualquer programador. O primeiro passo é criar duas tabelas: Uma delas irá conter as url’s com as imagens de cada nó e outra o cadastro do nó (TreeNode).

Diagrama do Banco de Dados
Banco  
Diagrama das Classes (DataContext)  
Datacontext  

Script para criação do Banco de dados

USE [dbTreeView]
GO
/****** Object: Table [dbo].[tbIcones] Script Date: 05/02/2010 01:17:11 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[tbIcones](
[IDIcone] [int] IDENTITY(1,1) NOT NULL,
[Descricao] [varchar](20) NOT NULL,
[urlImagem] [varchar](50) NOT NULL,
CONSTRAINT [PK_tbIcones] PRIMARY KEY CLUSTERED
(
[IDIcone] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
/****** Object: Table [dbo].[tbTreeView] Script Date: 05/02/2010 01:17:11 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[tbTreeView](
[IDNo] [int] IDENTITY(1,1) NOT NULL,
[Alias] [varchar](20) NOT NULL,
[ParentID] [int] NOT NULL,
[IDIcone] [int] NOT NULL,
CONSTRAINT [PK_tbTreeView] PRIMARY KEY CLUSTERED
(
[IDNo] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
/****** Object: ForeignKey [FK_tbTreeView_tbIcones] Script Date: 05/02/2010 01:17:11 ******/
ALTER TABLE [dbo].[tbTreeView] WITH CHECK ADD CONSTRAINT [FK_tbTreeView_tbIcones] FOREIGN KEY([IDIcone])
REFERENCES [dbo].[tbIcones] ([IDIcone])
GO
ALTER TABLE [dbo].[tbTreeView] CHECK CONSTRAINT [FK_tbTreeView_tbIcones]
GO

Tudo gerado, mãos a obra.

     Para preencher os nós e seus respectivos filhos teremos que utilizar recursividade no preenchimento dos TreeNode’s, vamos criar um método que recebe um objeto TreeView e o ID do nó como parâmetro que começaremos a preencher.

     No contrutor da classe Preenchimento(), atribuo coloco em memória os dados que utilizaremos (lista de ícones e Lista de nós).

private dbTreeViewDataContext _db;
private List<IconeEntidade> _icones;
private List<TreeViewEntidade> _TreeView;
public Preenchimento()
{
//Carrego tudo na memória para fazer as iterações
_db = new dbTreeViewDataContext();
//Como não faremos nenhum Update,desabilito a segmentação
//para evitar que o linq faça o mapeamento do que está sendo alterado
//com isso ganhamos performance.
_db.ObjectTrackingEnabled = false;
//Coloco em memória a lista de icones.
_icones = _db.IconeEntidades.ToList<IconeEntidade>();
//Coloco em memória a lista que contem os nós que será preenchida
_TreeView = _db.TreeViewEntidades.ToList<TreeViewEntidade>();

}

Agora vamos preencher os TreeNode’s pai e para cada TreeNode, preenchemos seus filhos.

public void PreencherTreeView(System.Web.UI.WebControls.TreeView objTreeView, int IDNoCarregar)
{
//Limpo os nodes existentes.
objTreeView.Nodes.Clear();

//passo por todos os nodes que foi passado como parâmetro para carregar. (organizando em ordem alfabética
foreach (var item in _TreeView.Where(p => p.ParentID == IDNoCarregar).OrderBy(p => p.ParentID).OrderBy(p => p.Alias))
{
//Preencho o nó pai
TreeNode nodePai = new TreeNode();
nodePai.Value = item.IDNo.ToString();
nodePai.Text = item.Alias;
nodePai.ImageToolTip = item.Alias;
nodePai.ImageUrl = _db.IconeEntidades.Where(p => p.IDIcone == item.IDIcone).FirstOrDefault().urlImagem;
//Preecho os filhos
PreencherNoFilho(nodePai);

//Adiciono o nó que foi preenchido
objTreeView.Nodes.Add(nodePai);
}

}

Para preencher os TreeNode’s filhos, recebemos o TreeNode pai (parent).

protected void PreencherNoFilho(TreeNode parentNode)
{
//Passo por todos os elementos filhos do nó pai
foreach (var item in _TreeView.Where(p => p.ParentID == int.Parse(parentNode.Value)).OrderBy(p => p.ParentID).OrderBy(p => p.Alias))
{

TreeNode noFiltro = new TreeNode(item.Alias,item.IDNo.ToString(),
_icones.Where(p => p.IDIcone == item.IDIcone).FirstOrDefault().urlImagem); //Adiciono a url da imagem
noFiltro.ImageToolTip = item.Alias; // Atribuo o texto que será exibido
noFiltro.SelectAction = TreeNodeSelectAction.SelectExpand; //Expando no nó.
parentNode.ChildNodes.Add(noFiltro); //adiciono na coleção de nós
PreencherNoFilho(noFiltro); //Preenchemos os filhos deste Node (recursividade)
}
}

Nossa estrutura pronta, vamos partir para a formatação.

Continua - Parte II

Continuando este artigo

     Vamos criar o arquivo de estilo da TreeView. (Estilo.css)

.TreeView{height:50px;color: #333333;position:absolute;clear: left;}
.TreeView p {border: 1px solid #999999;height: 15px;width: 250px;color: #666666;font-family: verdana;font-size: 9px;font-weight: bold;font-style: normal;background-color: #F7F7F7;padding: 5px 3px 3px 10px;}
.EstiloNo{font-family: Verdana; color: #333333; font-size: 10px; padding: 2px; margin-left: 2px;}
.EstiloNoCabecalho{ font-family: Verdana;color: #333333;font-size: 10px;padding: 2px;margin-left: 2px;font-weight: bold;}
.EstiloNoSelecionado{font-family: Verdana;color: #333333;font-size: 10px;padding: 2px;margin-left: 2px;font-style: italic;font-weight: bold;}


     Vamos criar o HTML, vejam que desabilitei o SessionState EnableSessionState”, claro que em um item como este não faz uma diferença significativa, mas, por boa prática, iremos desabilita-lo. Um dos grandes problemas com performance em projetos web é a habilitação de recursos que nunca são utilizados. (ViewState, SessionState e etc). Como a TreeView utiliza ViewState, deixei habilitado.

     Veja também, que ao utilizar o Ajax, habilitei no ScriptMananger a propriedade: EnablePartialRendering="true";

     No update panel, setei o modo de update para UpdateMode="Always"

     Por fim,  setei o objeto TreeView (AsyncPostBackTrigger) em uma Trigger dentro do UpdatePanel.

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="Minato.Exemplos.TreeView._Default" EnableSessionState="False" EnableViewState="true" %>

<!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 runat="server">
<title>Exemplo treeView Recursiva - Alexandre Minato</title>
<link href="App_Themes/Estilo.css" rel="stylesheet" type="text/css" />
</head>
<body>
<form id="frmPrincipal" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePartialRendering="true" />
<div class="TreeView">
<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Always">
<ContentTemplate>
<p><asp:Label ID="lblMensagem" runat="server" Text="Selecione um nó" /></p>
<asp:TreeView ID="objTreeView" runat="server" onselectednodechanged="objTreeView_SelectedNodeChanged">
<RootNodeStyle CssClass="EstiloNoCabecalho" />
<SelectedNodeStyle CssClass="EstiloNoSelecionado" />
<LevelStyles>
<asp:TreeNodeStyle CssClass="EstiloNo" />
</LevelStyles>
<NodeStyle CssClass="EstiloNo" />
</asp:TreeView>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="objTreeView" />
</Triggers>
</asp:UpdatePanel>
</div>
</form>
</body>
</html>
="true" />
<div class="TreeView">
<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Always">
<ContentTemplate>
<p><asp:Label ID="lblMensagem" runat="server" Text="Selecione um nó" /></p>
<asp:TreeView ID="objTreeView" runat="server" onselectednodechanged="objTreeView_SelectedNodeChanged">
<RootNodeStyle CssClass="EstiloNoCabecalho" />
<SelectedNodeStyle CssClass="EstiloNoSelecionado" />
<LevelStyles>
<asp:TreeNodeStyle CssClass="EstiloNo" />
</LevelStyles>
<NodeStyle CssClass="EstiloNo" />
</asp:TreeView>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="objTreeView" />
</Triggers>
</asp:UpdatePanel>
</div>
</form>
</body>
</html>

     Vamos colocar a funcionalidade no CodeBehind e pronto!!! Tudo funcionando.

protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
PreencherTreeView();

}

protected void PreencherTreeView()
{
using (Preenchimento preenchimento = new Preenchimento())
{
preenchimento.PreencherTreeView(objTreeView, 0);

}

}

protected void objTreeView_SelectedNodeChanged(object sender, EventArgs e)
{
lblMensagem.Text = String.Format("Nó selecionado: {0}", objTreeView.SelectedNode.Text);

}

Agora vamos ver o resultado final desta implementação

tv 

 Demo onLine

Abraços

Minato 8-)

Baixem a Solução

Minato , Criado em 27/03/2010, 23:51

      Recetemente tive problemas ao tentar utilizar o JQuery no meu site pessoal. Inclui a referência do js do JQuery no .aspx, na master Page e nada de funcionar, depois de alguns testes notei a propriedade Path dentro de ScriptReference…. e taí, funcionou!!!…

      Ou seja, para funcionar corretamente, inclua o ScriptManager na sua página, na Tag Script, inclua no ScriptReference o local onde está localizado o js.

   1: <asp:ScriptManager runat="server" ID="ScriptMananger1"> 
   2:  
   3: <Scripts> 
   4:  
   5:            <asp:ScriptReference Path="js/jquery/jquery-1.3.2.js" /> 
   6:  
   7: </Scripts> 
   8:  
   9: </asp:ScriptManager>

Espero ter ajudado.

Minato 8-)

 
teste