Nel progetto SharePoint al quale sto lavorando in questi giorni è uscita la necessità di mostrare l'elenco delle attività (presenti all'interno di una list Tasks normale) con delle formattazioni particolari. Ad esempio si volevano marcare con dei colori diversi le attività non completate ma già scadute o in procinto di scadere, le attività con scadenza entro 15 giorni, e così via. Una cosa tipo quello che rappresenta lo screenshot seguente:
Dopo una breve ricerca via web, ho trovato un attimo post -- Filtering and Formatting with Date Values -- presente nientemeno che sul blog del team di SharePoint Designer. L'esempio che propongono è proprio sulla colorazione di celle/righe in base alla differenza tra date; perfetto quindi. La soluzione si basa sull'utilizzo di SharePoint Designer (ovvio, visto dove si trova il post) per trasformare la ListView webpart standard in una DataView webpart e poi modificare pesantemente l'XSLT che renderizza la griglia con le attività, sfruttando dei template per calcolare la differenza tra le date e condizionalmente applicare stili custom.
Sebbene sembrasse perfettamente funzionante, dopo un po' di riflessioni ho deciso di abbandonare quella strada. Un po' per il fatto che sebbene lo comprenda l'XSLT non è il mio pane quotidiano, ma più che altro perchè questa soluzione non è particolarmente manutenibile, flessibile e riutilizzabile. Cosa accade infatti se voglio applicare lo stesso rendering custom su altre webpart delle attività (perchè magari ho più viste della stessa lista in homepage, con filtri diversi)? Dovrei rifare tutto lo stesso procedimento con SharePoint Designer. O perlomeno dovrei esportare l'XSLT modificato dalla prima webpart, applicarlo sulle altre e poi a mano correggere una serie di cose. Se dovesse saltare fuori un bug ovviamente la pezza andrebbe riapplicata ovunque. Se si dovesse fare un'ulteriore customizzazione, stesso discorso. Fino magari ad arrivare ad un punto dove la customizzazione non è neanche possibile (che so, la creazione di voci di menu contestuale personalizzate, il mix di dati provenienti da un'altra fonte, ecc.).
La soluzione verso la quale mi sono orientato è quindi stata quella di crearmi una webpart custom che mi permettesse di fare quello che volevo con il massimo della flessibilità e capacità di debugging. Per semplificarmi la vita ho usato la mitica SmartPart, una webpart "generica" che fa da contenitore di normali UserControl ASP.NET. Ho anche fatto riferimento ai seguenti 2 articoli che mostrano per bene come utilizzare il controllo SPGridView di SharePoint per creare una griglia con l'aspetto e tutte le caratteristiche delle griglie standard di SharePoint, ma caricate e gestite con una logica e dei dati custom:
- Displaying Data by Using the SPGridView Control in Windows SharePoint Services 3.0
- SPGridView and SPMenuField: Displaying custom data through SharePoint list
SPGridView eredita dalla classica GridView di ASP.NET, quindi c'è davvero poco da imparare per poterla usare. Si configurano le sue colonne, si ricava in qualche modo una DataTable (o un altro insieme di dati che implementa IListSource o IEnumerable), la si associa alla proprietà DataSource della griglia, si chiama DataBind, e il gioco è fatto. I dati potrebbero essere tranquillamente presi da un DB esterno, in tutto o in parte.
Nel mio caso volevo semplicemente mostrare il contenuto di una lista standard di SharePoint: una volta ottenuta una collezione SPListItemCollection la si può facilmente usare per creare una DataTable corrispondente grazie al suo metodo GetDataTable. Ricreata con poche righe la griglia dall'aspetto standard, per applicare le formattazioni custom basta intercettare l'evento OnRowCreated e modificare le proprietà dell'intera riga corrente o di una sua cella (BackColor o CssClass, ad esempio) in base alle proprie "regole di business".
Ora la domanda è: ok, hai duplicato la griglia standard e ci hai personalizzato l'aspetto...ma l'hai fatto in modo specifico per una singola vista con dei filtri prefissati...che succede se la vuoi applicare a viste diverse della stessa lista? E' semplice anche questo: è bastato aggiungere alla webpart una proprietà custom che permetta all'utente di specificare il nome di una delle viste di SharePoint create per la lista sorgente (ad esempio "Attività personali", "Attività in scadenza oggi" ecc.), e usare il modello ad oggetti di SharePoint per recuperare solo i dati di quella vista. Questo articolo che ho scritto ormai ben 3 anni fa spiega come fare (l'articolo richiede una registrazione gratuita al sito). Quindi non occorre neanche gestire N proprietà per specificare in modo complesso una serie predefinita di filtri, cercando di fornire una qualche flessibilità alla vista; basta solo scrivere quelle 5 righe per definire questa singola proprietà e poi lasciare a SharePoint il compito di ricavarsi i dati filtrati esattamente come avrebbe fatto per la sua UI standard, nonchè lasciare all'utente la possibilità di creare nuove viste (o di modificare quelle esistenti) con gli strumenti standard di SharePoint che già conosce.
Per la cronaca, lo screenshot in alto raffigura proprio la webpart custom creata. Non si sarebbe detto, visto che replica addirittura il menu contestuale, vero? (menu che è comunque possibile personalizzare con le proprie voci)
La webpart creata mi permetterà di aggiungere velocemente funzionalità a tutte le istanze sparse per il sito(i), correggere bug o modificare anche pesantemete l'aspetto della griglia...modificando, compilando e ri-deployando solo 2 file (il .ascx dello UserControl e il relativo assembly .dll). Seguendo la soluzione SharePoint Designer + XSLT le cose non sarebbero certamente state altrettanto semplici. In casi simili a questo, dove la flessibilità e il riutilizzo sono importanti, direi proprio che vale la pena affrontare il maggiore investimento iniziale (comunque molto contenuto).