JQuery UI consente facilmente di rappresentare i button con uno stile gradevole e personalizzabile, ad esempio il button in figura, nella versione normale e con rollover. Per altri esempi si può vedere il sito JQuery UI ThemeRoller.


Purtroppo lo stile viene applicato in automatico solo ai tag HTML button, ossia:
<button type="button">A button element</button>
Mentre non viene applicato ai tag HTML input di tipo button, ossia:
<input type="submit" value="A button element"/>
che è proprio il tag utilizzato per il rendering del button ASP.NET.
Per poter applicare lo stile di un tema JQuery UI ai button di ASP.NET, quindi, oltra a referenziare jQueryUI e il tema scelto, è necessario trasformare tutti i button ASP.NET in button HTML.
Ciò può essere fatto con jQuery stesso:
<script type="text/javascript">
$(document).ready(function () {
$('input:submit, input:reset, input[type=button]').button();
});
</script>
In questo modo jQuery UI si occuperà automaticamente dello stile dei button, applicando il tema scelto.
Se però i button sono all’interno di un UpdatePanel della pagina ASPX, ad ogni PostBack asincrono ci sarà una brutta sorpresa, in quanto i button torneranno al loro aspetto classico. Infatti l’evento $(document).ready avviene solo al caricamento del documento, e non dopo un PostBack asincrono. Per questo è necessario intercettare l’evento PageLoaded del framework AJAX di Microsoft e inserire lì il codice per la trasformazione dei button.
Il codice allora diventa:
<script type="text/javascript">
$(document).ready(function () {
Sys.WebForms.PageRequestManager.getInstance().add_pageLoaded(
function () {
// qui viene eseguito dopo un postback asincrono
SetupButtons();
});
// qui viene eseguito dopo il primo caricamento del documento
SetupButtons();
});
function SetupButtons() {
$('input:submit, input:reset, input[type=button]').button();
}
</script>
Utilizzando questo codice, tuttavia, mi è capitato di ricevere l’errore “Sys is undefined” effettuando un semplice refresh con la pagina con Internet Explorer 9.
Non mi sono chiare le cause, probabilmente il refresh su IE9 causa l’esecuzione del codice in $(document).ready prima del caricamento del framework Microsoft AJAX.
Un possibile workaround che ho usato per risolvere il problema consiste nel verificare il caricamento del framework prima di provare ad usare Sys.WebForms.PageRequestManager.getInstance(), riprovando dopo 100 ms nel caso in cui Sys risulti undefined. Ecco il codice:
<script type="text/javascript">
$(document).ready(function () {
setupDocument();
});
function setupDocument() {
if (typeof Sys != "undefined") {
Sys.WebForms.PageRequestManager.getInstance().add_pageLoaded(
function () {
SetupButtons();
});
SetupButtons();
} else {
setTimeout(SetupDocument, 100);
}
}
function SetupButtons() {
$('input:submit, input:reset, input[type=button]').button();
}
</script>
Attraverso un HttpHandler è possibile generare al volo un’immagine e restituirla al chiamante. L’immagine generata può tenere conto, ad esempio, di parametri passati nella query string, oppure di parametri della stessa richiesta, o altro ancora, e le possibili applicazioni sono infinite.
Come esempio di applicazione, supponiamo di voler visualizzare in una pagina web l’indirizzo IP di chi sta visualizzando la pagina.
L’indirizzo IP può essere facilmente ricavato dalla Request dell’HttpContext, ossia, nel CodeBehind di una pagina ASP.NET:
string ipAddress = Page.Request.UserHostAddress;
o più in generale:
string ipAddress = HttpContext.Current.Request.UserHostAddress;
Ci possono essere dei casi in cui non è possibile o è scomodo intervenire direttamente nel codice della pagina web. Ad esempio, se si volesse visualizzare l’indirizzo del chiamante in un post di questo blog o, in generale, in una pagina web HTML.
Una possibile soluzione è l’utilizzo di un HttpHandler, purché si abbia a disposizione un host raggiungibile su cui pubblicarlo. In tal caso nella pagina HTML o nel post del blog basta inserire un’immagine, con il semplice tag img:
<img src="http://imagehandlers.lucabarbi.net/VisualizeIP.ashx" alt="indirizzo IP" />
All’indirizzo indicato un HttpHandler si occuperà di recuperare l’indirizzo IP dalla Request e restituire un’immagine generata al volo con la scritta dell’indirizzo IP.
Per generare un’immagine png trasparente con la scritta dell’indirizzo IP consideriamo ad esempio il codice:
/// <summary>
/// Genera un'immagine con l'indirizzo IP del chiamante
/// </summary>
/// <param name="ipAddress"></param>
/// <returns></returns>
private Bitmap CreateImageFromIp(string ipAddress)
{
// crea l'immagine bitmap
var immagine = new Bitmap(180, 21);
// crea un oggetto grafico per disegnare
var grafico = Graphics.FromImage(immagine);
// imposta lo sfondo
var backgroundColor = Color.White;
grafico.Clear(backgroundColor);
// scrive l'ip passato
var brush = Brushes.Blue;
var font = new Font("Tahoma", 9, FontStyle.Regular);
var startPosition = new Point(2, 2);
grafico.DrawString(string.Format(
"Il tuo IP è: {0}", ipAddress), font, brush, startPosition);
// rende lo sfondo trasparente
immagine.MakeTransparent(backgroundColor);
return immagine;
}
Quindi l’HttpHandler (VisualizeIP.ashx) diventa semplicemente:
public void ProcessRequest(HttpContext context)
{
var a = HttpContext.Current.Request.UserHostAddress;
var request = context.Request;
var ipAddress = request.UserHostAddress;
var response = context.Response;
response.ContentType = "image/png";
var immagine = CreateImageFromIp(ipAddress);
immagine.Save(response.OutputStream, ImageFormat.Png);
response.Flush();
response.End();
}
public bool IsReusable
{
get
{
return false;
}
}
Il risultato è l’immagine seguente:

In allegato i sorgenti dell'esempio: ImageHandlers.zip (15,83 kb)
Con jQuery.UI è possibile creare un’interfaccia utente a tab in una pagina web con pochissimo codice.
Ad esempio, consideriamo la pagina ASP.NET seguente:
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Tabs with jQueri.UI</title>
<link rel="Stylesheet"
href="http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.17/themes/smoothness/jquery-ui.css" />
<script type="text/javascript"
src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.1.min.js" ></script>
<script type="text/javascript"
src="http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.17/jquery-ui.min.js" ></script>
<script type="text/javascript">
$(function () {
$("#tabs").tabs();
});
</script>
</head>
<body>
<form id="form1" runat="server">
<div id="tabs">
<ul>
<li><a href="#tabPresentazione">Presentazione</a></li>
<li><a href="#tabPortfolio">Portfolio</a></li>
<li><a href="#tabContatti">Contatti</a></li>
</ul>
<div id="tabPresentazione">
<h2>Chi siamo</h2>
<p>... </p>
</div>
<div id="tabPortfolio">
<h2>I nostri prodotti</h2>
<p>...</p>
</div>
<div id="tabContatti">
<h2>I nostri recapiti</h2>
<p>...</p>
</div>
</div>
</form>
</body>
</html>
Il risultato sarà un’interfaccia a tabs come quella in figura:

Che cosa succede se nella pagina è inserito un controllo che effettua il postback? Ad esempio consideriamo un semplice LinkButton nel tab Contatti.
<div id="tabContatti">
<h2>I nostri recapiti</h2>
<p>... </p>
<asp:LinkButton id="lbPostBack" runat="server">
Clicca per un postback
</asp:LinkButton>
</div>
Corrispondente all'immagine seguente:

Dopo il postback, la pagina viene ricaricata e il primo tab ritorna ad essere il tab attivo e ciò può costituire un problema. Per risolverlo ci sono diverse soluzioni, quella che mi piace di più l’ho trovata qui su Stack Overflow (non è quella indicata come risposta migliore, ma è la più votata) e consiste nel memorizzare il tab corrente in un controllo di tipo HiddenField, il cui valore è persistito nel ViewState della pagina e recuperato dopo il postback.
Pertanto è sufficiente inserire nella form precedente un controllo HiddenField:
<form id="form1" runat="server">
<asp:HiddenField runat="server" ID="hfLastTab" Value="0" />
<div id="tabs">
e aggiungere il seguente pezzo di codice javascript nella sezione head del precedente esempio:
$(function () {
$("#tabs").tabs({
show: function () {
var sel = $('#tabs').tabs('option', 'selected');
$("#<%= hfLastTab.ClientID %>").val(sel);
},
selected: '<%= hfLastTab.Value %>'
});
});
e a questo punto si può vedere come il tab selezionato rimanga attivo anche dopo un pòostback.
In allegato la pagina aspx di esempio, WebFormForTabs.zip (2,96 kb)
Le web.config transformation sono dei file xml che contengono le istruzioni per trasformare durante il deploy il file di Web.config di un’applicazione web. Il file di transform è legato, oltre che al Web.config, alla configurazione, per cui la web.config Transformation Engine di Visual Studio 2010, quando si effettua il publish dell’applicazione web, trasformerà il file Web.config in base al file di trasformazione della configurazione selezionata (ad esempio Web.Release.config) per produrre un file Web.config pronto per la pubblicazione.

Un’applicazione web viene creata già con le due configurazioni di default, Debug e Release, ed i corrispondenti file di transform.
In questo modo si possono predisporre modifiche al file di configurazione comode per un deploy in ambiente di produzione, con, ad esempio, valori differenti per le stringhe di connessione o per specifici appSettings.
Nel file Web.Release.config, creato di default, è già predisposta la trasformazione per rimuovere l’attributo “debug” alla sezione compilation di system.web del Web.config. Per ulteriori informazioni sulle potenzialità e sulla sintassi delle Web.config transform si può far riferimento a questo articolo su MSDN Blogs nella sezione relativa ai Web Development Tools.
Quindi se si ha un file Web.config con:
<system.web>
<compilation debug="true">
e con Web,Release.config in cui si ha:
<system.web>
<compilation xdt:Transform="RemoveAttributes(debug)" />
Pubblicando l’applicazione per la configurazione release, il file Web.config generato avrà rimosso l’attributo debug:
<system.web>
<compilation>
Tutto quanto visto funziona al momento della pubblicazione dell’applicazione. Può però essere comodo utilizzare la stessa funzionalità anche in fase di sviluppo.
Per esempio, recentemente mi è capitato di dover lavorare su un’applicazione web che, attraverso opportune modifiche al Web.config (appSettings, configurazioni custom, connection string) viene pubblicata in tre diversi modi, per tre siti differenti.
In fase di sviluppo era necessario modificare tali valori abbastanza frequentemente, per testare il comportamento dell’applicazione nelle tre diverse configurazioni. È perciò nata l’esigenza di automatizzare il cambio di contesto.
Per prima cosa si devono creare tre diverse configurazioni per lo sviluppo nei tre ambienti e tre corrispondenti configurazioni per il deploy dei tre ambienti, attraverso il Configuration Manager di Visual Studio.

Dopo aver creato le configurazioni, si fanno generare a Visual Studio i file di trasformazione, posizionandosi in Solution Explorer sul file Web.config e scegliendo dal menu contestuale “Add Config Transform”.
Quindi si è aggiunge al progetto un nuovo file di configurazione, chiamato WebTemplate.config, con l’idea di utilizzarlo per sovrascrivere il file Web.config ad ogni compilazione, in cui si copia il contenuto del Web.config originario.
A questo punto bisogna fare in modo che Visual Studio provveda in automatico a trasformare il file WebTemplate.config utilizzando il file transform corrispondente alla configurazione selezionata, e lo utilizzi per sovrascrivere il Web.config all’avvio dell’applicazione (F5).
Si può fare tutto modificando il file di progetto dell’applicazione web. Per farlo da Visual Studio, anzitutto bisogna effettuare l’operazione di unload sul file di progetto (tasto destro, Unload Project). Quindi si può effettuare la modifica del file, sempre col tasto destro sul progetto scegliendo “Edit NomeProgetto.csproj”.
In fondo al file XML ci sono due target, individuati col nome BeforeBuild e AfterBuild, che in un progetto creato con Visual Studio appaiono commentati.
<!-- To modify your build process, add your task inside one of the targets below
and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
Nel target BeforeBuild possiamo introdurre le azioni di copia e trasformazione del file di configurazione, ad esempio come di seguito:
<Target Name="BeforeBuild">
<CallTarget Targets="UpdateWebConfig" />
</Target>
<Target Name="UpdateWebConfig">
<CallTarget Targets="CopyFromTemplate" />
<CallTarget Targets="ApplyConfigTransform" />
</Target>
<Target Name="CopyFromTemplate">
<Message Text="Writing web.config from template" />
<Copy SourceFiles="WebTemplate.config" DestinationFiles="Web.config" />
</Target>
<Target Name="ApplyConfigTransform">
<Message Text="Applying transformation for configuration $(Configuration)" />
<TransformXml Source="WebTemplate.config" Transform="Web.$(Configuration).config"
Destination="Web.config" />
</Target>
Sempre in questo file, cerchiamo i file di trasformazione facciamo in modo che compaiano nella solution come trasformazioni di WebTemplate.config e che non vengano inclusi, insieme allo stesso WebTemplate.config, nei file del pacchetto di publish.
Questo si può ottenere semplicemente modificando le righe:
<Content Include="WebTemplate.config">
<SubType>Designer</SubType>
</Content>
<Content Include="Web.Debug.config">
<DependentUpon>Web.config</DependentUpon>
</Content>
...
in questo modo:
<None Include="WebTemplate.config">
<SubType>Designer</SubType>
</None>
<None Include="Web.Debug.config">
<DependentUpon>WebTemplate.config</DependentUpon>
</None>
...
Si salva il file così modificato e poi si ricarica, posizionandosi in Solution Explorer sul file di progetto e scegliendo col tasto destro “Reload Project”.
Se il progetto utilizza un sistema di source control, si deve escludere il file Web.config dal source control per poterne consentire la sovrascrittura senza che ciò risulti in un cambiamento del codice e che comporti il dover mettere in check out il file. Ad esempio con TFS si può selezionare il file Web.config da Solution Explorer e dal menu “File -> Source Control” escluderlo dal controllo come in figura.

Tutto è pronto per poter utilizzare i file di trasformazione in fase di sviluppo.
Attenzione: quando si avvia l'applicazione non si deve tenere aperto nel progetto il file Web.config, altrimenti Visual Studio sembra fare riferimento al file originario, anche se poi si può verificare come l'applicazione avviata effettivamente si riferisca al file generato dalle trasformazioni.
Per esempio, se si utilizza un WebTemplate.config con il debug attivato ed una configurazione di Release il cui transform file provvede ad eliminare il debug dal web.config, si potrà vedere come avviando il debug dell'applicazione con la configurazione Release (e il Web.config non aperto in Visual Studio) si riceve l'avviso di Visual Studio che non è possibile effettuare il debug.

Passando alla modalità Debug, il cui file transform non elimina l’attributo debug, invece, il debug si avvia senza problemi.
I siti web ASP.NET utilizzano algoritmi per criptare, decifrare e validare il viewstate, i dati di autenticazione mediante form e l’identificazione della sessione ASP.NET in modalità out of process, quindi per esempio per siti pubblicati su più server di una server farm.
Gli algoritmi e le relative chiavi di validazione e decrittazione sono configurabili nel file web.config attraverso l’elemento machineKey.
Le impostazioni di default di IIS prevedono che ad ogni sito sia assegnata automaticamente una chiave di validazione e una per decriptare. Però queste impostazioni non vanno bene, ad esempio, per siti pubblicati in load balancing su una web farm, poiché per consentire alla sessione di seguire l’utente mentre viene dirottato da un server verso un altro, è necessario che su tutti i server gli algoritmi e le chiavi coincidano.
È necessario, perciò, generare le chiavi e per farlo si possono utilizzare i numerosissimi tool on line, oltre che scriversene uno seguendo gli altrettanto numerosi tutorial on line.
Oppure si può usare lo stesso IIS 7 (o successivo) per configurare gli algoritmi e generare le chiavi, come suggerito qui, attraverso la funzionalità offerta da IIS Manager.

Dal sito che ci interessa, cliccando su “Chiave computer” si accede alla funzionalità specifica, in cui si può deselezionare l’opzione di generazione automatica in fase di esecuzione e poi, cliccando su “Genera chiavi”, far generare le chiavi.

Applicando le modifiche, nel file web.config del sito viene scritto l’elemento machineKey, ad esempio:
<configuration>
<system.web>
<machineKey decryption="AES" decryptionKey="99CF7A9B2A1D1B954A1800A714C3BFD0927AEAD93DBEA93B"
validationKey=
"F53F821100A97C0718E481ACDE9EDDFBA360A8882A4F88ECC29D6029D9053CE1A94EC95A29C51556E19C6B918DB342F8B78C634AA59CC4C3CE0D86A0BE3CFB16"
/>
</system.web>
</configuration>
Gli stessi valori dovranno essere riportati nei web.config del sito di tutti i server della web farm.
JSON (JavaScript Object Notation) è un formato compatto per lo scambio di dati molto adatto per applicazioni client/server, specialmente se si vuole ridurre l’utilizzo di banda.
Per poter inviare dati attraverso applicazioni .NET è sufficiente utilizzare quanto ci mette a disposizione .NET attraverso DataContractJsonSerializer (namespace System.Runtime.Serialization.Json).
Consideriamo, ad esempio, una classe come la seguente:
public class SampleItem
{
public SampleItem()
{
Date = DateTime.Now;
Number = new Random(DateTime.Now.Millisecond).Next(1, 101);
}
public DateTime Date { get; set; }
public int Number { get; set; }
}
In pratica ogni istanza di questa classe è creata con la data di creazione e un numero casuale tra 1 e 100.
Possiamo scrivere un semplice HttpHandler che ci risponda inviandoci una nuova istanza della classe SampleItem, serializzata secondo JSON, come nel codice seguente:
using System.Web;
using System.IO;
using System.Runtime.Serialization.Json;
using System.Text;
public class GetData : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
var response = context.Response;
var sample = new SampleItem();
using (var ms = new MemoryStream())
{
var serializer = new DataContractJsonSerializer(typeof(SampleItem));
serializer.WriteObject(ms, sample);
context.Response.ContentType = "application/json";
response.Write(Encoding.Default.GetString(ms.ToArray()));
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
A questo punto non resta che preparare una semplice pagina web in grado di consumare questi dati. Ad esempio, una pagina con un pulsante di start che fa partire una richiesta asincrona e quindi un timer per ripetere la richiesta ogni 100ms. Il risultato verrà aggiunto ad una tabella, mentre un pulsante stop servirà a fermare le richieste.
Il codice HTML è il seguente:
<input type="submit" value="Start"
onclick="startSampling();return false;" id="btnStart" />
<input type="submit" value="Stop"
onclick="stopSampling();return false;" id="btnStop"
disabled="disabled" />
<table id="samplesTable">
<tr>
<th>
Data
</th>
<th>
Valore
</th>
</tr>
</table>
Mentre il codice javascript ha le due funzionalità di start e stop:
var timerId;
function startSampling() {
$('#btnStart').attr('disabled', 'disabled');
$('#btnStop').removeAttr('disabled');
getSample();
}
function stopSampling() {
$('#btnStop').attr('disabled', 'disabled');
$('#btnStart').removeAttr('disabled');
if (timerId) {
clearTimeout(timerId);
};
}
Lo stop, oltre ad abilitare lo start e disabilitare lo stop, blocca il timer ed evita che partano le successive richieste. Per inviare la richiesta si usa la funzione getSample:
function getSample() {
$.ajax({
url: "/GetData.ashx",
contentType: "application/json; charset=utf-8",
responseType: "json",
cache: false,
success: OnComplete,
error: OnFail
});
timerId = setTimeout('getSample()', 100);
}
function OnComplete(result) {
addRow($('#samplesTable'),
getDateTimeFormatted(getDateFromAspNetString(result.Date)), result.Number);
}
function OnFail() {
alert('Errore nella ricezione dei dati');
}
Viene inviata una chiamata asincrona all’url corrispondente all’HttpHandler visto prima e, in caso di risposta, viene aggiunta una riga alla tabella. è necessario impostare il parametro cache a false, altrimenti
Seguono le funzioni javascript per aggiungere la riga e formattare la data in formato JSON / ASP.NET AJAX, come indicato qui:
function addRow(table, date, value) {
var newRow = '<tr><td>' + date + '</td><td class="value">' + value + '</td></tr>';
table.each(function () {
$(this).append(newRow);
});
}
function getDateFromAspNetString(aspNetString) {
var milliseconds = aspNetString.replace(
/^\/Date\(([0-9]+)([+-][0-9]{4})?\)\/$/,
'$1');
if (milliseconds != aspNetString) {
return new Date(parseInt(milliseconds));
}
}
function getDateTimeFormatted(date) {
return getString(date.getDate(), 2) + '/' + getString(date.getMonth() + 1, 2) + '/'
+ date.getFullYear() + ' ' + getString(date.getHours(), 2) + ':'
+ getString(date.getMinutes(), 2) + ':' + getString(date.getSeconds(), 2) + '.'
+ date.getMilliseconds();
}
function getString(number, chars) {
n = String(number);
while (n.length < chars) {
n = "0" + n;
}
return n;
}
In allegato il codice di esempio: JSonSample.zip (10,34 kb)
Tempo fa avevo il problema di far lavorare Expression Web nella root del web server di sviluppo del framework, invece che sotto una directory virtuale. Avevo risolto lo stesso problema per Visual Studio 2005, ma questa volta però non sono stato capace di trovare nulla (né in rete né tra le opzioni del programma).
Allora mi è venuto in mente di aver letto questo post (per l'autore: hai visto che a qualcuno è servito? ;-)), in cui si spiega come sia possibile avviare manualmente il web server di sviluppo, ossia il file WebDev.Webserver.exe che si trova nella directory %WINDIR%\Microsoft.NET\Framework\v2.0.50727
Le istruzioni per l'uso sono visualizzabili digitando da linea di comando:
%WINDIR%\Microsoft.NET\Framework\v2.0.50727\WebDev.Webserver.exe /?
che produce in output:
ASP.NET Development Server Usage:
WebDev.WebServer /port:<port number> /path:<physical path> [/vpath:<virtual path>]
port number:
[Optional] An unused port number between 1 and 65535.
The default is 80 (usable if you do not also have IIS listening on the same port).
physical path:
A valid directory name where the Web application is rooted.
virtual path:
[Optional] The virtual path or application root in the form of '/<app name>'.
The default is simply '/'.
Example:
WebDev.WebServer /port:8080 /path:"c:\inetpub\wwwroot\MyApp" /vpath:"/MyApp"
You can then access the Web application using a URL of the form:
http://localhost:8080/MyApp
Per risolvere il mio problema è bastato quindi lanciare il comando:
WebDev.WebServer /path:"c:\miosito"
(poiché avevo anche bisogno di lavorare sulla porta 80, oltre che nella root)
Sempre sul post di Paolo Ongari ci sono, invece, le istruzioni per un file batch completo.
In un sito web a cui sto lavorando ho inserito in una pagina il controllo Tabs dell'AJAX Control Toolkit. In questa pagina avevo l'esigenza di permettere al visitatore di cambiare il tab visibile anche mediante un link nella pagina stessa.
All'inizio ho provato semplicemente con un LinkButton inserito in un UpdatePanel, modificando dal lato server la proprietà ActiveTabIndex del TabContainer. Questa soluzione, semplicissima da implementare (anche se probabilmente genera parecchio codice superfluo), creava problemi con il rendering di una mappa visualizzata in uno dei tab (problema di cui ho scritto in un precedente post).
Allora ho provato ad utilizzare JavaScript, ma un primo abbozzo che sembrava funzionare senza problemi, in realtà si è dimostrato compatibile solo con IE (ho provato IE7, non so su IE6) e non con Firefox.
Dopo qualche inutile tentativo per rendere il mio approccio compatibile anche con Firefox, in questo post ho trovato la spiegazione del metodo giusto per affrontare il problema.
Il trucco è nel riferirsi al Behavior corrispondente al controllo (come sempre per i controlli dell'AJAX Control Toolkit), per il quale si trovano esposti i metodi e le proprietà "pubblici"[1], accessibili lato client. Per accedere al Behavior, è sufficiente riferirsi in JavaScript alla proprietà control del TabContainer.
Riassumo qui come fare.
Dato un controllo Tabs, costituito da un TabContainer col nome MyTabs e dai TabPanel interni ad esso, ad esempio:
<ajaxToolKit:TabContainer ID="MyTabs" runat="server">
<ajaxToolKit:TabPanel runat="server" ID="tab1">
<HeaderTemplate> Uno </HeaderTemplate>
<ContentTemplate>
Primo pannello
</ContentTemplate>
</ajaxToolKit:TabPanel>
<ajaxToolKit:TabPanel runat="server" ID="tab2">
<HeaderTemplate> Due </HeaderTemplate>
<ContentTemplate>
Secondo pannello
</ContentTemplate>
</ajaxToolKit:TabPanel>
<ajaxToolKit:TabPanel runat="server" ID="tab3">
<HeaderTemplate> Tre </HeaderTemplate>
<ContentTemplate>
Terzo pannello
</ContentTemplate>
</ajaxToolKit:TabPanel>
</ajaxToolKit:TabContainer>
Basterà inserire nella pagina il seguente codice JavaScript:
function changeTab( tabIndex ){
var tabBehavior = $get('<%=MyTabs.ClientID%>').control;
tabBehavior.set_activeTabIndex(tabIndex);
}
A questo punto un semplice collegamento ipertestuale, inserito in un punto qualsiasi della pagina (e quindi anche in uno dei TabPanel) può essere sufficiente a richiamare la funzione.
Ad esempio:
<a href="javascript:changeTab(1);">Vai al secondo tab</a>
[1] Trattandosi di JavaScript, non ha molto senso parlare di metodi, proprietà, pubblico e privato, anche se sia nella libreria AJAX di Microsoft che in quelle dell'AJAX Control Toolkit sono state adottate convenzioni per i nomi che rendono la programmazione in JavaScript simile alla programmazione ad oggetti. Per approfondimenti sul tema si può partire da
questo post di
Andrea Boschin.