Informazioni sui trigger UpdatePanel di ASP.NET AJAX
di Scott Cate
Quando si lavora nell'editor di markup in Visual Studio, è possibile notare (da IntelliSense) che sono presenti due elementi figlio di un controllo UpdatePanel. Uno dei quali è l'elemento Triggers, che specifica i controlli nella pagina (o il controllo utente, se si usa uno) che attiverà un rendering parziale del controllo UpdatePanel in cui risiede l'elemento.
Introduzione
La tecnologia di ASP.NET Microsoft offre un modello di programmazione orientato agli oggetti e basato sugli eventi e lo unisce ai vantaggi del codice compilato. Tuttavia, il modello di elaborazione lato server presenta diversi svantaggi intrinseci nella tecnologia, molti dei quali possono essere risolti dalle nuove funzionalità incluse in Microsoft ASP.NET 3.5 AJAX Extensions. Queste estensioni consentono molte nuove funzionalità client avanzate, tra cui il rendering parziale delle pagine senza richiedere un aggiornamento a pagina completa, la possibilità di accedere ai servizi Web tramite script client (inclusa l'API di profilatura ASP.NET) e un'API lato client estesa progettata per eseguire il mirroring di molti degli schemi di controllo visualizzati nel set di controlli sul lato server ASP.NET.
Questo white paper esamina la funzionalità Trigger XML del componente ASP.NET AJAX UpdatePanel
. I trigger XML offrono un controllo granulare sui componenti che possono causare il rendering parziale per controlli UpdatePanel specifici.
Questo white paper si basa sulla versione Beta 2 di .NET Framework 3.5 e Visual Studio 2008. Le estensioni ASP.NET AJAX, in precedenza un assembly aggiuntivo destinato a ASP.NET 2.0, sono ora integrate nella libreria di classi di base di .NET Framework. Questo white paper presuppone inoltre che si stia usando Visual Studio 2008, non Visual Web Developer Express e verranno fornite procedure dettagliate in base all'interfaccia utente di Visual Studio (anche se gli elenchi di codice saranno completamente compatibili indipendentemente dall'ambiente di sviluppo).
Trigger
I trigger per un determinato UpdatePanel, per impostazione predefinita, includono automaticamente tutti i controlli figlio che richiamano un postback, inclusi (ad esempio) i controlli TextBox con la relativa AutoPostBack
proprietà impostata su true. Tuttavia, i trigger possono essere inclusi in modo dichiarativo anche tramite markup; questa operazione viene eseguita all'interno della <triggers>
sezione della dichiarazione del controllo UpdatePanel. Anche se è possibile accedere ai trigger tramite la Triggers
proprietà della raccolta, è consigliabile registrare tutti i trigger di rendering parziale in fase di esecuzione (ad esempio, se un controllo non è disponibile in fase di progettazione) usando il RegisterAsyncPostBackControl(Control)
metodo dell'oggetto ScriptManager per la pagina, all'interno dell'evento Page_Load
. Tenere presente che Pages è senza stato e quindi è consigliabile registrare nuovamente questi controlli ogni volta che vengono creati.
L'inclusione automatica dei trigger figlio può anche essere disabilitata (in modo che i controlli figlio che creano postback non attivino automaticamente il rendering parziale) impostando la ChildrenAsTriggers
proprietà su false. Ciò consente la massima flessibilità nell'assegnazione dei controlli specifici che possono richiamare un rendering di pagina ed è consigliabile, in modo che uno sviluppatore acconsente a rispondere a un evento, anziché gestire gli eventi che possono verificarsi.
Si noti che quando i controlli UpdatePanel sono annidati, quando UpdateMode è impostato su Condizionale, se viene attivato UpdatePanel figlio, ma l'elemento padre non è , verrà aggiornato solo updatePanel figlio. Tuttavia, se updatePanel padre viene aggiornato, verrà aggiornato anche UpdatePanel figlio.
Elemento <Triggers>
Quando si lavora nell'editor di markup in Visual Studio, è possibile notare (da IntelliSense) che sono presenti due elementi figlio di un UpdatePanel
controllo. L'elemento visualizzato più di frequente è l'elemento <ContentTemplate>
, che incapsula essenzialmente il contenuto che verrà mantenuto dal pannello di aggiornamento (il contenuto per il quale viene abilitato il rendering parziale). L'altro elemento è l'elemento <Triggers>
, che specifica i controlli nella pagina (o il controllo utente, se si usa uno) che attiverà un rendering parziale del controllo UpdatePanel in cui risiede l'elemento <Triggers> .
L'elemento <Triggers>
può contenere un numero qualsiasi di due nodi figlio: <asp:AsyncPostBackTrigger>
e <asp:PostBackTrigger>
. Entrambi accettano due attributi ControlID
e EventName
e possono specificare qualsiasi controllo all'interno dell'unità corrente di incapsulamento (ad esempio, se il controllo UpdatePanel si trova all'interno di un controllo utente Web, non è consigliabile tentare di fare riferimento a un controllo nella pagina in cui risiederà il controllo utente).
L'elemento <asp:AsyncPostBackTrigger>
è particolarmente utile in quanto può essere indirizzato a qualsiasi evento da un controllo Control esistente come elemento figlio di qualsiasi controllo UpdatePanel nell'unità di incapsulamento, non solo da UpdatePanel in cui questo trigger è figlio. Pertanto, qualsiasi controllo può essere eseguito per attivare un aggiornamento parziale della pagina.
Analogamente, l'elemento <asp:PostBackTrigger>
può essere usato per attivare il rendering di una pagina parziale, ma uno che richiede un round trip completo al server. Questo elemento trigger può essere usato anche per forzare il rendering di una pagina intera quando un controllo altrimenti attiva un rendering di pagina parziale (ad esempio, quando un Button
controllo esiste nell'elemento <ContentTemplate>
di un controllo UpdatePanel). Anche in questo caso, l'elemento PostBackTrigger può specificare qualsiasi controllo figlio di qualsiasi controllo UpdatePanel nell'unità corrente di incapsulamento.
<Informazioni di riferimento per gli elementi Triggers>
Discendenti di markup:
Tag | Descrizione |
---|---|
<asp:AsyncPostBackTrigger> | Specifica un controllo e un evento che causeranno un aggiornamento parziale della pagina per UpdatePanel che contiene questo riferimento al trigger. |
<asp:PostBackTrigger> | Specifica un controllo e un evento che causeranno un aggiornamento a pagina completa (aggiornamento a pagina completa). Questo tag può essere usato per forzare un aggiornamento completo quando un controllo attiva altrimenti il rendering parziale. |
Procedura dettagliata: Trigger Cross-UpdatePanel
- Creare una nuova pagina ASP.NET con un oggetto ScriptManager impostato per abilitare il rendering parziale. Aggiungere due UpdatePanel a questa pagina: nella prima, includere un controllo Label (Label1) e due controlli Button (Button1 e Button2). Button1 dovrebbe dire Fare clic per aggiornare entrambi e Button2 dovrebbe dire Fare clic per aggiornare questo o qualcosa lungo queste righe. Nel secondo UpdatePanel includere solo un controllo Label (Label2), ma impostarne la proprietà ForeColor su un valore diverso da quello predefinito per distinguerlo.
- Impostare la proprietà UpdateMode di entrambi i tag UpdatePanel su Condizionale.
Listato 1: Markup per default.aspx:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!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>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager EnablePartialRendering="true"
ID="ScriptManager1" runat="server"></asp:ScriptManager>
<div>
<asp:UpdatePanel ID="UpdatePanel1" runat="server"
UpdateMode="Conditional">
<ContentTemplate>
<asp:Label ID="Label1" runat="server" />
<br />
<asp:Button ID="Button1" runat="server"
Text="Update Both Panels" OnClick="Button1_Click" />
<asp:Button ID="Button2" runat="server"
Text="Update This Panel" OnClick="Button2_Click" />
</ContentTemplate>
</asp:UpdatePanel>
<asp:UpdatePanel ID="UpdatePanel2" runat="server"
UpdateMode="Conditional">
<ContentTemplate>
<asp:Label ID="Label2" runat="server" ForeColor="red" />
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="Button1" EventName="Click" />
</Triggers>
</asp:UpdatePanel>
</div>
</form>
</body>
</html>
- Nel gestore eventi Click per Button1 impostare Label1.Text e Label2.Text su un valore dipendente dal tempo, ad esempio DateTime.Now.ToLongTimeString()). Per il gestore eventi Click per Button2, impostare solo Label1.Text sul valore dipendente dal tempo.
Listato 2: Codebehind (tagliato) in default.aspx.cs:
public partial class _Default : System.Web.UI.Page
{
protected void Button1_Click(object sender, EventArgs e)
{
Label1.Text = DateTime.Now.ToLongTimeString();
Label2.Text = DateTime.Now.ToLongTimeString();
}
protected void Button2_Click(object sender, EventArgs e)
{
Label1.Text = DateTime.Now.ToLongTimeString();
}
}
- Premere F5 per compilare ed eseguire il progetto. Si noti che, quando si fa clic su Aggiorna entrambi i pannelli, entrambe le etichette cambiano testo; tuttavia, quando si fa clic su Aggiorna questo pannello, vengono aggiornati solo Label1.
(Fare clic per visualizzare l'immagine a dimensione intera)
Sotto il cofano
Usando l'esempio appena costruito, è possibile esaminare le operazioni che ASP.NET AJAX sta facendo e come funzionano i trigger tra pannelli UpdatePanel. A tale scopo, si lavorerà con il codice HTML dell'origine della pagina generata, nonché con l'estensione Mozilla Firefox denominata FireBug. Con esso, è possibile esaminare facilmente i postback AJAX. Si userà anche lo strumento .NET Reflector di Lutz Roeder. Entrambi questi strumenti sono liberamente disponibili online e sono disponibili con una ricerca su Internet.
Un esame del codice sorgente della pagina non mostra quasi nulla fuori dal normale; Il rendering dei controlli UpdatePanel viene eseguito come <div>
contenitori ed è possibile vedere che la risorsa script include fornita da <asp:ScriptManager>
. Esistono anche alcune nuove chiamate specifiche di AJAX a PageRequestManager interne alla libreria di script client AJAX. Infine, vengono visualizzati i due contenitori UpdatePanel, uno con i pulsanti di cui è stato <input>
eseguito il rendering con i due <asp:Label>
controlli di cui è stato eseguito il rendering come <span>
contenitori. Se si esamina l'albero DOM in FireBug, si noterà che le etichette sono in grigio per indicare che non producono contenuto visibile.
Fare clic sul pulsante Aggiorna questo pannello e notare che il controllo UpdatePanel superiore verrà aggiornato con l'ora del server corrente. In FireBug scegliere la scheda Console in modo da poter esaminare la richiesta. Esaminare prima i parametri della richiesta POST:
(Fare clic per visualizzare l'immagine a dimensione intera)
Si noti che UpdatePanel ha indicato al codice AJAX sul lato server esattamente quale albero di controllo è stato generato tramite il parametro ScriptManager1: Button1
del UpdatePanel1
controllo. Fare clic sul pulsante Aggiorna entrambi i pannelli. Quindi, esaminando la risposta, viene visualizzata una serie delimitata da pipe di variabili impostate in una stringa; in particolare, vediamo che l'elemento UpdatePanel principale, UpdatePanel1
, ha l'intero codice HTML inviato al browser. La libreria di script client AJAX sostituisce il contenuto HTML originale di UpdatePanel con il nuovo contenuto tramite la .innerHTML
proprietà e quindi il server invia il contenuto modificato dal server come HTML.
Fare ora clic sul pulsante Aggiorna entrambi i pannelli ed esaminare i risultati dal server. I risultati sono molto simili: entrambi i UpdatePanel ricevono il nuovo CODICE HTML dal server. Come per il callback precedente, viene inviato uno stato di pagina aggiuntivo.
Come si può notare, poiché non viene usato alcun codice speciale per eseguire un postback AJAX, la libreria di script client AJAX è in grado di intercettare i postback dei moduli senza codice aggiuntivo. I controlli server utilizzano automaticamente JavaScript in modo che non inviino automaticamente il modulo: ASP.NET inserisce automaticamente il codice per la convalida e lo stato dei moduli, principalmente ottenuto dall'inclusione automatica delle risorse script, dalla classe PostBackOptions e dalla classe ClientScriptManager.
Si consideri ad esempio un controllo CheckBox; esaminare il disassembly della classe in .NET Reflector. A tale scopo, assicurarsi che l'assembly System.Web sia aperto e passare alla System.Web.UI.WebControls.CheckBox
classe , aprendo il RenderInputTag
metodo . Cercare un'istruzione condizionale che controlla la AutoPostBack
proprietà :
(Fare clic per visualizzare l'immagine a dimensione intera)
Quando il postback automatico è abilitato in un CheckBox
controllo (tramite la proprietà AutoPostBack impostata su true), il rendering del tag risultante <input>
viene quindi eseguito con uno script di gestione degli eventi ASP.NET nel relativo onclick
attributo. L'intercettazione dell'invio del modulo, quindi, consente di inserire ASP.NET AJAX nella pagina in modo non invadente, contribuendo a evitare eventuali potenziali modifiche che potrebbero verificarsi utilizzando una sostituzione di stringa possibilmente imprecisa. Inoltre, ciò consente a qualsiasi controllo personalizzato di ASP.NET di utilizzare la potenza di ASP.NET AJAX senza codice aggiuntivo per supportarne l'uso all'interno di un contenitore UpdatePanel.
La <triggers>
funzionalità corrisponde ai valori inizializzati nella chiamata PageRequestManager a _updateControls . Si noti che la libreria di script client ASP.NET AJAX utilizza la convenzione che i metodi, gli eventi e i nomi dei campi che iniziano con un carattere di sottolineatura vengono contrassegnati come interni e non sono destinati all'uso all'esterno della libreria stessa. Con esso, è possibile osservare quali controlli sono destinati a causare postback AJAX.
Ad esempio, aggiungiamo due controlli aggiuntivi alla pagina, lasciando un controllo all'esterno dei Controlli UpdatePanel completamente e lasciando uno all'interno di un UpdatePanel. Verrà aggiunto un controllo CheckBox all'interno dell'elemento UpdatePanel superiore e verrà visualizzato un controllo DropDownList con diversi colori definiti all'interno dell'elenco. Ecco il nuovo markup:
Elenco 3: Nuovo markup
<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!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="Head1" runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager EnablePartialRendering="true"
ID="ScriptManager1" runat="server"></asp:ScriptManager>
<div>
<asp:UpdatePanel ID="UpdatePanel1" runat="server"
UpdateMode="Conditional">
<ContentTemplate>
<asp:Label ID="Label1" runat="server" /><br />
<asp:Button ID="Button1" runat="server"
Text="Update Both Panels" OnClick="Button1_Click" />
<asp:Button ID="Button2" runat="server"
Text="Update This Panel" OnClick="Button2_Click" />
<asp:CheckBox ID="cbDate" runat="server"
Text="Include Date" AutoPostBack="false"
OnCheckedChanged="cbDate_CheckedChanged" />
</ContentTemplate>
</asp:UpdatePanel>
<asp:UpdatePanel ID="UpdatePanel2" runat="server"
UpdateMode="Conditional">
<ContentTemplate>
<asp:Label ID="Label2" runat="server"
ForeColor="red" />
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="Button1"
EventName="Click" />
<asp:AsyncPostBackTrigger ControlID="ddlColor"
EventName="SelectedIndexChanged" />
</Triggers>
</asp:UpdatePanel>
<asp:DropDownList ID="ddlColor" runat="server"
AutoPostBack="true"
OnSelectedIndexChanged="ddlColor_SelectedIndexChanged">
<asp:ListItem Selected="true" Value="Red" />
<asp:ListItem Value="Blue" />
<asp:ListItem Value="Green" />
</asp:DropDownList>
</div>
</form>
</body>
</html>
Di seguito è riportato il nuovo code-behind:
Elenco 4: Codebehind
public partial class _Default : System.Web.UI.Page
{
protected void Button1_Click(object sender, EventArgs e)
{
if (cbDate.Checked)
{
Label1.Text = DateTime.Now.ToString("MM/dd/yyyy hh:mm:ss");
Label2.Text = DateTime.Now.ToString("MM/dd/yyyy hh:mm:ss");
}
else
{
Label1.Text = DateTime.Now.ToLongTimeString();
Label2.Text = DateTime.Now.ToLongTimeString();
}
}
protected void Button2_Click(object sender, EventArgs e)
{
if (cbDate.Checked)
{
Label1.Text = DateTime.Now.ToString("MM/dd/yyyy hh:mm:ss");
}
else
{
Label1.Text = DateTime.Now.ToLongTimeString();
}
}
protected void cbDate_CheckedChanged(object sender, EventArgs e)
{
cbDate.Font.Bold = cbDate.Checked;
}
protected void ddlColor_SelectedIndexChanged(object sender, EventArgs e)
{
Color c = Color.FromName(ddlColor.SelectedValue);
Label2.ForeColor = c;
}
}
L'idea alla base di questa pagina è che l'elenco a discesa seleziona uno dei tre colori per visualizzare la seconda etichetta, che la casella di controllo determina se è in grassetto e se le etichette visualizzano la data e l'ora. La casella di controllo non deve causare un aggiornamento AJAX, ma l'elenco a discesa deve, anche se non è ospitato in un UpdatePanel.
(Fare clic per visualizzare l'immagine full-size)
Come è evidente nella schermata precedente, il pulsante più recente da fare clic era il pulsante destro Aggiorna questo pannello, che ha aggiornato la prima volta indipendente dall'ora inferiore. La data è stata disattivata anche tra clic, perché la data è visibile nell'etichetta inferiore. Infine, è il colore dell'etichetta inferiore: è stato aggiornato più di recente rispetto al testo dell'etichetta, che dimostra che lo stato del controllo è importante e gli utenti si aspettano che venga mantenuto tramite postback AJAX. Tuttavia, l'ora non è stata aggiornata. L'ora è stata ripopolata automaticamente tramite la persistenza del campo __VIEWSTATE della pagina interpretata dal runtime di ASP.NET quando il controllo è stato nuovamente eseguito il rendering nel server. Il codice del server AJAX ASP.NET non riconosce i metodi in cui i controlli cambiano stato; viene semplicemente ripopolato dallo stato di visualizzazione e quindi esegue gli eventi appropriati.
Deve essere sottolineato, tuttavia, che aveva inizializzato il tempo entro l'evento Page_Load, il tempo sarebbe stato incrementato correttamente. Di conseguenza, gli sviluppatori devono essere consapevoli che il codice appropriato viene eseguito durante i gestori eventi appropriati ed evitare l'uso di Page_Load quando un gestore eventi di controllo sarebbe appropriato.
Riepilogo
Il controllo UpdatePanel delle estensioni AJAX ASP.NET è versatile e può usare diversi metodi per identificare gli eventi di controllo che devono causare l'aggiornamento. Supporta l'aggiornamento automatico dai controlli figlio, ma può anche rispondere agli eventi di controllo altrove nella pagina.
Per ridurre il potenziale di caricamento dell'elaborazione del server, è consigliabile impostare la ChildrenAsTriggers
proprietà di un oggetto UpdatePanel su false
e che gli eventi vengano espliciti anziché inclusi per impostazione predefinita. Ciò impedisce anche a eventuali eventi non necessari di causare effetti potenzialmente indesiderati, tra cui la convalida e le modifiche ai campi di input. Questi tipi di bug possono essere difficili da isolare, perché la pagina viene aggiornata in modo trasparente all'utente e la causa potrebbe pertanto non essere immediatamente ovvia.
Esaminando i lavori interni del modello di modulo ASP.NET AJAX dopo l'intercettazione, è stato possibile determinare che usa il framework già fornito da ASP.NET. In questo modo, mantiene la massima compatibilità con i controlli progettati usando lo stesso framework e intrusa minimamente in qualsiasi javaScript aggiuntivo scritto per la pagina.
Biografia
Rob Paveza è uno sviluppatore di applicazioni .NET senior di Terralever (www.terralever.com), una società di marketing interattiva leader in Tempe, AZ. Può essere raggiunto a robpaveza@gmail.com, e il suo blog si trova a http://geekswithblogs.net/robp/.
Scott Cate ha lavorato con le tecnologie Web Microsoft dal 1997 ed è il presidente di myKB.com (www.myKB.com) dove si è specializzato nella scrittura di applicazioni basate su ASP.NET incentrate sulle soluzioni software knowledge base. Scott può essere contattato tramite posta elettronica all'indirizzo o al suo blog all'indirizzo scott.cate@myKB.comScottCate.com