Come applicare i temi di jQuery UI ai button di ASP.NET

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.

 button con jQuery UIbutton con jQuery UI rollover

 

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>

Una macro Visual Studio per debug di web application sotto IIS (attach w3wp.exe)

Quando si deve effettuare il debug di web application sotto IIS (ad esempio una WebPart di SharePoint), è necessario effettuare l'attach del processo (w3wp.exe) da Visual Studio.

Questa operazione, comprensiva di prompt di conferma, comporta ogni volta l'esecuzione di azioni ripetitive e perdita di tempo:

  • Menù debug -> Attach to Process
  • selezione del processo (o dei processi) w3wp.exe
  • click su Attach
  • conferma per ognuno dei processi

È possibile scriversi una macro di Visual Studio in grado di eseguire tutte queste operazioni, magari avviandola con un click da un tasto della toolbar.

In rete ci sono decine di esempi, qui riporto il codice che ho trovato in giro e personalizzato per usare questa macro alcune decine di volte al giorno (almeno in questo periodo).

Imports System
Imports EnvDTE
Imports EnvDTE80
Imports EnvDTE90
Imports EnvDTE90a
Imports EnvDTE100
Imports System.Diagnostics

Public Module AttachToIIS

    Public Sub AttachToWebServer()
        Dim W3WP As String = "w3wp.exe"
        If Not (AttachToProcess(W3WP)) Then
            System.Windows.Forms.MessageBox.Show("Can't find IIS process")
        End If
    End Sub

    Public Function AttachToProcess(ByVal ProcessName As String) As Boolean
        Dim Processes As EnvDTE.Processes = DTE.Debugger.LocalProcesses
        Dim Process As EnvDTE.Process
        Dim ProcessFound As Boolean = False
        For Each Process In Processes
            If (Process.Name.Substring(Process.Name.LastIndexOf("\") + 1) = ProcessName) Then
                Process.Attach()
                ProcessFound = True
            End If
        Next
        AttachToProcess = ProcessFound
    End Function

End Module

 

 Qui si possono trovare, invece, tutte le informazioni di carattere generale sulle macro di Visual Studio.

Sbloccare file in checkout o lock da parte di altri utenti in TFS

Lavorando in team con TFS, può capitare di non riuscire ad effettuare alcune operazioni poiché ci sono file in lock da parte di altri utenti, che non sono più nel team, oppure su workspace che non sono più disponibili (ad esempio se il computer è stato formattato).

Ad esempio, se si devono spostare dei file da una cartella ad un'altra, un'operazione tipica di quando si vuole creare un branch. In tal caso, se c'è anche un solo file in lock da parte di qualche utente, TFS segnala l'errore.

Per rimediare, è possibile effettuare l'undo del checkout da linea di comando, purché in possesso dei necessari requisiti di amministratore. La sintassi è la seguente:

tf undo [/workspace:workspacename[;workspaceowner]] [/server:servername] [/recursive] itemspec [/noprompt]

Tutti i dettagli in questo post sul blog di Mike Bevers.

Generatore di Lorem ipsum

Quando si deve mostrare un layout di un sito web è molto comodo usare un testo riempitivo non piatto, per dare un aspetto gradevole. L’esempio per antonomasia è il classico “Lorem ipsum”, In rete se ne possono trovare diversi esempi da copiare e incollare, oppure si può usare uno dei tanti generatori come lipsum.com, che permette di selezionare anche il numero di paragrafi, parole, byte o il numero di elementi di un elenco.

Oppure è possibile copiare e incollare da qui :-)

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean nec magna non felis egestas tempus non non odio. Suspendisse potenti. Morbi fringilla varius posuere. Vestibulum laoreet nibh in odio gravida viverra. Aenean malesuada tortor et tellus gravida molestie. Suspendisse iaculis vehicula risus non ultricies. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Maecenas vulputate libero magna. Morbi eget mauris eu massa consequat accumsan. Praesent convallis velit a sem luctus luctus. Aliquam erat volutpat. Sed a enim eget nisl volutpat convallis. Mauris leo lectus, fringilla ut pulvinar eget, mattis vel leo. Pellentesque nec elit nec neque euismod tempor in ut ligula. Phasellus id elit erat. Sed nec dui leo, vel egestas velit.

Aliquam ut quam sapien, ut pulvinar nibh. Cras mollis, ipsum at aliquam malesuada, velit metus viverra ante, vitae vulputate sem risus ac turpis. Quisque sollicitudin sapien vel lacus hendrerit bibendum. Sed sollicitudin scelerisque velit, euismod vehicula elit porttitor sit amet. Aliquam erat volutpat. Donec risus orci, egestas ac suscipit ut, aliquam rutrum sapien. Curabitur dapibus, sapien vitae sodales vestibulum, felis ante posuere magna, quis blandit arcu neque in nunc. Nunc posuere, justo vel imperdiet convallis, sapien tortor tempor quam, sit amet vulputate eros leo sed libero. Nunc augue lacus, ultricies eu porttitor vitae, tempus at lacus. Aenean vitae nunc quam. Sed eleifend lorem eget nunc volutpat convallis. Donec tincidunt, odio vitae semper venenatis, urna purus lobortis felis, eu fermentum risus leo in nisl. Cras felis lectus, convallis nec iaculis a, iaculis pellentesque diam. Nulla eleifend gravida tempor. Sed erat augue, molestie ut accumsan sit amet, lacinia eu lacus. Duis nisl neque, egestas gravida tempus a, luctus eget orci.

Cras id risus sem, sit amet euismod sem. Morbi semper accumsan consequat. Curabitur pellentesque velit non arcu ornare id tincidunt odio feugiat. Nullam id porta nulla. Curabitur varius, mi vel ornare euismod, risus neque ullamcorper nulla, at faucibus elit justo sit amet dolor. Fusce in elit lacus, ac commodo libero. Aenean commodo, dolor et fringilla rhoncus, risus dolor eleifend risus, a hendrerit nunc odio nec tellus. Vestibulum feugiat vulputate neque vitae scelerisque. Vestibulum arcu orci, tristique elementum faucibus ac, egestas nec orci. Morbi posuere leo a orci laoreet sagittis. Proin eleifend mi pharetra magna rhoncus mollis. In tincidunt semper quam, ac mollis metus tempus vitae. Cras consectetur adipiscing sem sed dictum. Fusce aliquet facilisis dolor at placerat. Integer fringilla volutpat imperdiet. Maecenas blandit gravida sem quis interdum.

Donec ultrices, tellus id ornare sodales, leo felis ultrices ligula, vel egestas sapien nibh a urna. Nulla ac odio metus. Etiam auctor convallis sollicitudin. Sed diam dui, imperdiet id varius congue, rutrum vitae mauris. Quisque sit amet sem et arcu vestibulum commodo. Maecenas dignissim ipsum vel sem vestibulum non ornare lectus ultrices. Curabitur vehicula ipsum eget mauris blandit faucibus. Cras id nunc eget ipsum vestibulum blandit. Aenean vel felis at nisl auctor convallis. Donec placerat consectetur metus, ac convallis erat placerat eu. Pellentesque sit amet consectetur elit. Proin convallis est eu nibh viverra ullamcorper.

Fusce odio orci, blandit a commodo sodales, lobortis sit amet massa. Mauris at nisl dolor. Donec id est magna, ut gravida massa. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Duis felis nisl, gravida nec tincidunt nec, feugiat in ipsum. Quisque sagittis molestie tellus, a suscipit metus rhoncus in. Maecenas vitae dignissim urna.

Generare un’immagine dinamicamente attraverso un HttpHandler che visualizza l’indirizzo IP

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)

 

Come mantenere il tab corrente dopo un postback utilizzando i tabs di jQuery.UI

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:

screenshot di un'interfaccia con tabs ottenuta con jQuery.UI

 

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:

screenshot interfaccia con tabs e postback

 

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)

Ottimizzare le immagini di un sito web per velocizzare il caricamento della pagina

Image Optimizer è una extension di Visual Studio 2010, scaricabile dalla Visual Studio Gallery, in grado di ottimizzare le immagini di tipo jpg, png e gif riducendone le dimensioni senza perdite di qualità.

Si installa anche direttamente da Visual Studio (Tools –> Extension Manager) e, una volta installata, permette di ottimizzare immagini o cartelle di immagini semplicemente cliccandoci sopra col tasto destro e selezionando Optimize image.

Undelete in Team Foundation Server

Quando si elimina un file sotto TFS e si esegue il check in, il file viene eliminato dal Workspace e dal file system e lo stesso accadrà nei Workspace degli altri utenti, quando effettueranno il Get Latest.

Il file, tuttavia, non è stato eliminato da TFS ed è ancora possibile vederlo da Source Control Explorer, attivando l’opzione Show deleted items in the Source Control Explorer (Tools –> Options –> Source Control –>Visual Studio Team Foundation Server).

image

Una volta attivata l’opzione, in Source Control Explorer sono visualizzati i file eliminati e, cliccando su di essi col tasto destro del mouse, è possibile eseguire l’operazione di undelete.

image

Per eliminare definitivamente un file da TFS, invece, è necessario ricorrere alla CLI ed eseguire il comando tf destroy, il cui utilizzo è descritto qui su MSDN.

Il comando tf destroy causa l’eliminazione irreversibile di un file o cartella, va perciò usato con cautela e solo in caso di necessità (ad esempio virus o file molto grandi inclusi per errore).