Il blog di Sandro Rizzetto

Syncfusion, probabilmente la più completa libreria di componenti Blazor

 

To read an English version (auto-translated with AI tools) click here...

Nel mondo degli sviluppatori di applicazioni enterprise vi sono due scuole di pensiero riguardo le librerie di componenti: c’è chi dice che non servono, che sono “black box” di cui ti devi fidare alla cieca e che se non va qualcosa sono guai; e chi -come il sottoscritto- le reputa un tool necessario e “inevitabile” per risparmiare tempo e per dare all’utilizzatore sempre la miglior experience in fatto di UI e usability.

Ho già parlato in svariati post di diverse librerie di componenti Blazor che nel corso di questi anni ho usato per side projects personali e applicazioni reali. Librerie commerciali come DevExpress (il backoffice di mtb.rizzetto.com) o free (o che all’epoca lo erano) come Blazorise (progetto Geo-Italy), MudBlazor (progetto myReviews) e Radzen (progetto meteo-altoadige).

Era arrivato il momento di testare quella che forse è la più famosa e ricca e che con Telerik si contende la palma di regina, ovvero la libreria Syncfusion che si avvale di più di 85 componenti.

Riuscire a scrivere una review su tutti i componenti sarebbe un’impresa titanica, mi limiterò quindi a descrivere alcune impressioni d’uso di un paio di mesi di utilizzo.

Il campo di applicazione è stata una webapp Blazor 8 SSR+Server Side per la gestione di una fittizia scuola di MTB per bambini, perché mi sembrava un bel esempio dove poter testare alcuni componenti che non fossero le classiche griglie o di data-entry (textbox, dropdown, ecc).

Completezza dei componenti

La prima cosa che salta all’occhio guardando le demo o la documentazione dei vari componenti è l’enorme massa di parametri, metodi ed eventi che espongono. Se certe volte questo potrebbe anche rivelarsi un “difetto” perché introduce una certa complessità all’uso, quando ne hai bisogno diventa fondamentale. Qui si vede che la libreria non è certo nata ieri (ma nel 2001) e gli anni e anni di esperienza fatta sulle piattaforme precedenti (dai gloriosi tempi di WinForms, WPF o per restare nel web Asp.Net, MVC, e tutte le piattaforme JS-based) è stata migrata nella libreria Blazor, che è bene ricordare NON è un wrapper JS come era agli albori ma è stata riscritta completamente in C# per offrire prestazioni al top. Per tornare in tema, ogni componente quindi offre tantissime opzioni per essere cucito su misura alle proprie esigenze, e se anche non vi fosse la proprietà o il metodo che serve, il support riesce sempre a trovare il workaround per ovviare alla mancanza.

Gantt e Kanban

Un grossissimo pregio di questa libreria è la presenza di alcuni componenti che gli altri competitor non hanno proprio. Se l’applicazione a cui stai lavorando ha esplicitamente bisogno di uno o entrambi questi componenti, non c’è storia, devi rivolgerti a chi ce li ha.

Il componente di visualizzazione di un diagramma Gantt è estremamente complesso e articolato e non posso dire che sia un mini Microsoft Projects, ma poco ci manca. Gestisce out-of-the box l’editing di un item con i classici campi name, start, end, duration (peccato solo in days e non in mons o altre unità di misura come fa Project), progress ma anche tutti i campi per la gestione delle dependency con una UI articolata per scegliere il predecessor e la modalità (FS, SS, ecc.). Se quindi già avere la parte grafica è un enorme aiuto, non doversi fare le dialog di add/edit item è un plus incredibile.

Anche il componente per fare un Kanban è un unicum che non ho trovato in nessun’altra libreria e sebbene più semplice, offre comunque quello che serve a una semplice gestione “agile” di workitems come le user stories a cui assegnare un nome, una persona, una status (che diventa la colonna in cui si trova la card) e che si può gestire con il classico drag ‘n drop sia per passare da uno stato all’altro, sia per essere dato ad un’altra persona (drag su swimlane diverse).

Unico difetto a cui mi hanno detto stanno lavorando è che lo status deve essere una proprietà di tipo string (“ToDo”, “Done”) e non un Id o un riferimento ad una lookup table esterna.

DataGrid

Ogni libreria che si rispetti deve avere una sua Data Grid più o meno articolata e ovviamente anche Syncfusion ha la sua che si rivela molto completa.

La cosa che mi è piaciuta da subito è l’editing dell’item in una Dialog Form autocostruita; non amo infatti, se non per griglie di dati molto semplici e con poche colonne, l’editing in-line dentro la riga e preferisco una popup modale con più spazio e più chiara.

Peccato che manchino due proprietà legate alla singola colonna (tipo due bool ShowInGrid, ShowInForm) che sarebbero molto comode per visualizzare un field nella griglia e non nella form e viceversa. Il supporto tecnico mi ha comunque offerto due soluzioni semplici, la prima basata su due righe di css e la seconda molto banale ovvero di settare a zero la width della colonna che vogliamo solo in edit.

 .e-gridform .e-table .e-rowcell:has(.e-disabled) {
     display: none;
 }

Ho trovato molto comoda la colonna per le Foreign Key dove si può fornire, oltre al Field che fa da Id, la collection dei valori e la proprietà da mostrare nella dropdown che viene automaticamente mostrata nella finestra di add/edit (ma non nel filtro).

A proposito di filtri… quelli invece non mi sono piaciuti e li ho trovati inferiori ad altre librerie come ad esempio Radzen. In automatico NON viene renderizzato un componente specifico per il tipo di colonna (es. un datetime picker per le date o un checkbox per i boolean) e bisogna arrangiarsi ogni volta con template custom e con chiamate a metodi non tipizzati (qui un esempio).

Nell'esempio sopra vediamo una griglia e il suo dialogform generato automaticamente. Come vedete dallo snippet del codice sotto il Country è una Foreign key sulla tabella Countries, le note vengono visualizzate nel form ma non nella griglia, il Level viceversa.

 <GridColumns>
     <GridColumn Field="@nameof(Participant.Id)" HeaderText="Id" IsPrimaryKey="true" IsIdentity="true" Visible="false"></GridColumn>
     <GridColumn Field="@nameof(Participant.FirstName)" HeaderText="FirstName"></GridColumn>
     <GridColumn Field="@nameof(Participant.LastName)" HeaderText="LastName"></GridColumn>
     <GridColumn Field="@nameof(Participant.Email)" HeaderText="E-Mail"></GridColumn>
     <GridForeignColumn Field="@nameof(Participant.CountryId)" HeaderText="Country" TValue="Country" ForeignDataSource="Countries" ForeignKeyField="Id" ForeignKeyValue="CountryName"></GridForeignColumn>
     <GridColumn Field="@nameof(Participant.DateOfBirth)" HeaderText="Date of Birth" Format="d" Width="150px" ></GridColumn>
    
     <GridColumn Field="@nameof(Participant.Recurring)" HeaderText="Recurring" DisplayAsCheckBox="true" Width="100px" TextAlign="TextAlign.Center">
         <FilterTemplate>
             <SfCheckBox TChecked="bool?"  @bind-Checked="@FilterRecurringChecked"></SfCheckBox>
             <SfButton CssClass="e-small" >X</SfButton>
         </FilterTemplate>
     </GridColumn>
     <GridColumn Field="@nameof(Participant.Notes)" HeaderText="Notes" Width="0px">
         <EditTemplate>
             <label class="e-label-top" for="Project">Notes:</label>
             <SfTextBox Multiline=true Placeholder="Notes..." @bind-Value="@((context as Participant).Notes)"></SfTextBox>
         </EditTemplate>
     </GridColumn>
     <GridColumn Field="@nameof(Participant.BikeLevel)" HeaderText="Level" AllowEditing="false"></GridColumn>
 </GridColumns>

Data Form

Se invece i campi di un Model da editare sono molti e si vuole creare una apposita pagina, allora conviene usare la Data Form. Si tratta di un componente molto comodo per realizzare velocemente delle Forms di input passando una serie di <FormItems> che andranno a comporre le righe (o le colonne dato che è possibile splittare la form con un ColumnCount e ColumnSpan) e gestiscono automaticamente validazione e submit. Mi è piaciuto molto la possibilità di usare la FluentValidation invece che la classica DataAnnotions che presuppone di avere dei DTO solo per l’input oppure di “sporcare” con gli attributi le classi POCO (o quelle “scaffolded” di EF Core). Alla fine, non è nulla di trascendentale (io infatti me ne ero fatta una simile dove i FormItems altro non erano che dei div flex con un ChildContent) ma non doversi gestire template, layout, localization, floating labels, ecc. è un bel risparmio di tempo.

<SfDataForm ID="MyForm" Model="@Data" ColumnCount="2" ColumnSpacing="20px">
    <FormValidator>
        <DataAnnotationsValidator></DataAnnotationsValidator>
    </FormValidator>
    <FormItems>
        <FormItem Field="@nameof(Data.FirstName)" LabelText="First Name"></FormItem>
        <FormItem Field="@nameof(Data.LastName)" LabelText="Last Name"></FormItem>
        <FormItem Field="@nameof(Data.Address)" LabelText="Address"></FormItem>
        <FormItem Field="@nameof(Data.City)" LabelText="City"></FormItem>
        <FormItem Field="@nameof(Data.Phone)" LabelText="Phone"></FormItem>
        <FormItem Field="@nameof(Data.MobilePhone)" LabelText="Mobile"></FormItem>
        <FormItem Field="@nameof(Data.DateOfBirth)" LabelText="Date of Birth" EditorType="FormEditorType.DatePicker"></FormItem>
        <FormItem Field="@nameof(Data.Recurring)" LabelText="Already Customer" EditorType="FormEditorType.Switch"></FormItem>
        <FormItem Field="@nameof(Data.Notes)" EditorType="FormEditorType.TextArea" ColumnSpan="2" LabelText="Notes"></FormItem>
    </FormItems>
    <FormButtons>
        <SfButton typeof="submit" IsPrimary="true">Register</SfButton>
        <SfButton typeof="button" CssClass="e-danger">Delete</SfButton>
    </FormButtons>
</SfDataForm>

 

Templates

Un aspetto che riguarda tutti i componenti è la possibilità omni-presente di poter modificare il template dell’item su cui stiamo lavorando; che sia la card del kanban, o quella del calendario del componente Scheduler (potente e completo anche lui) o la riga di una datagrid, ecc. all’utente viene sempre data la possibilità di cambiare a piacere il layout grafico con uno completamente custom, visto che il context dell’item o della riga viene sempre messo a disposizione.

Anche nella Data Grid la libertà di templetizzare la singola cella o tutta la riga offre possibilità molto ampie; come vedete qui sotto ad esempio con pochissimo codice mi sono fatto un gestore dei logs di Serilog “liberamente copiato ispirato” al famoso Seq

TreeGrid e Diagram

Un altro componente che non ho visto in altre librerie è la TreeGrid utile per gestire items con gradi di parentship a N livelli quali ad esempio le Hierarchy Collection (un organigramma, una product breakdown structure, ecc.)

Molto comoda, ma l’ho testata con una collection grande (1000 elementi) e si è rivelata molto lenta. La cosa può essere risolta usando il LoadChildOnDemand, ma l'esperienza d’uso non è la stessa e anche il search e i filtri ovviamente non funzionano come quando carichiamo tutto l’albero in una volta.

Le stesse collection gerarchiche possono poi essere facilmente visualizzate con un altro componente molto complesso e che da solo potrebbe valere parecchi Euro di costo, ovvero il Diagram. Qui ad esempio potete vedere come l’organigramma di esempio di cui sopra potrebbe essere visualizzato, ma se scorrete il menu di sinistra potete capire quanti tipologie di diagrammi, tutti editabili e manipolabili, possono essere creati.

 

Rich Text Editor e Word Processor

In quasi tutte le applicazioni backoffice che ho scritto nella mia carriera ho avuto bisogno di un mini-editor HTML e ovviamente la libreria ci viene in aiuto con un semplice ed efficace Rich Text Editor che ha tutte le funzionalità che di solito servono. Ma se vogliamo qualcosa di più e l’html non basta? Qui entra in gioco un altro componente che fa la differenza e “stacca” la concorrenza, ovvero un vero e proprio Word Processor compatibile con il format docx di Ms-Word. Ho provato a caricare svariati documenti anche molto complessi con molte immagini, tabelle, figure, ecc. e si è sempre comportato benissimo. L’unica volta che ha “fallito” è stato nel caricare una formula inserita con l’Equation Editor, però direi che si tratta di casi limite.

Word Library (DocIO)

E se i documenti Word li volessi creare non con un editor ma via codice? Oppure da un template che poi iterato con una collection mi crea un “mail-merge”? Ecco che ci viene in aiuto uno dei 4 componenti della Document Processing Library (Word, Excel, PowerPoint, PDF) con cui è praticamente possibile creare via codice un qualsiasi documento Office o Pdf. Sono veramente potenti anche se non sempre di semplice apprendimento, ma con l’aiuto dei forum, del support o dei molti esempi si riesce veramente a implementare nella propria app delle gestioni enterprise molto avanzate (es. la creazione di ordini, fatture, dei diplomi di fine corso, ecc.)

Technical Support: ticket, forum, feedback portal, bug reporting

A proposito di aiuti da parte del personale tecnico… qui siamo a livelli veramente altissimi! All’inizio ero un po’ sconcertato dal fatto di avere tanti (troppi?) metodi per chiedere aiuto, tanto che… ho chiesto aiuto su come chiedere aiuto😊.

A parte la piattaforma per fare suggerimenti e quella per segnalare bug, pensavo che i ticket (rivolti immagino solo a chi paga la licenza) fossero più rapidi ed esaustivi del forum che dovrebbe essere uno strumento free della community. Invece ho capito che dipende molto da chi risponde… alcune volte l’incaricato che ha preso in carico il ticket mi ha saputo aiutare, in altre occasione è stato molto semplificativo (“non si può fare”) e fatta la stessa domanda sul forum invece ho avuto la soluzione desiderata. Sempre sul forum ho trovato in una particolare feature che mi serviva una persona che non solo me l’ha risolta, ma tramite il suo sample me l’ha praticamente scritta al 90%. Insomma, quasi sempre grandissima competenza e disponibilità da parte del technical staff a levarti dagli impicci e a fornirti più aiuto possibile.

Documentazione, Demo e Playground

Il terzo elemento (insieme a qualità dei componenti e del support) che di solito considero è quello relativo alla Documentazione e anche qui non possiamo di sicuro lamentarci. Si hanno due “filoni” principali di documentazione, uno di sole demo ed esempi (sempre corredati dai sorgenti) e uno più tecnico che però non è la solita documentazione automatica creata dal codice, ma comunque qualcosa di molto discorsivo e con molti pezzi di codice. Ecco forse sarebbe meglio riunire i due mondi ed avere un unico punto di entrata del componente (es. la home della “Data Grid” da cui poi navigare o nelle demo o nella documentazione) perché mi sono ritrovato spesso a non ricordarmi se la tal feature l’avevo letta di qua o di là.

Molto utile e simpatico il Playground (sullo stile di CodePen di js) con cui scrivere degli snippet di codice da provare al volo. È un po’ lento (anzi parecchio!) e quando escono nuovi service pack mi è capitato che non funzionasse più finché non cancellavo la cache delle dll webassembly. Diventa uno strumento comodissimo per passare pezzi di codice al support (si genera uno short url che dura 90 giorni) senza mandare in giro zip di progetti o repo github pubblici. Ed inoltre può servire per testare vecchie versioni della libreria (o pre-testare passaggi a nuove release) o diversi tipi di temi.

Pricing e Licensing

Siamo arrivati al punto “dolente” di questa fantastica libreria ovvero il prezzo (onestamente parecchio più alto dei competitors, quasi 4X!) e il modello di licensing. È giusto infatti sapere che a differenza di altre librerie, non esiste un primo prezzo di acquisto e un successivo canone di manutenzione, ma si parte subito con una subscription (mensile o annuale) e se si smette di pagare l’applicazione non funzionerà più emettendo un popup che ne impedisce il proseguimento. Si tratta quindi più che di un canone di una “royalty” perenne che devo essere in grado di sostenere facendomi pagare a mia volta dal mio cliente (oppure l’ho sfruttata per tante apps o ho venduto il prodotto così bene e con così tanto markup che posso permettermi l’esborso).

Esiste comunque un licenza Community Free non solo per progetti no-profit single developer, ma anche per piccole organizzazioni (fatturato inferiore a 1 milione, max 5 developers e 10 impiegati) che possono chiederne l’applicazione.

Forse (ma avranno sicuramente già fatto le loro valutazioni) sarebbe utile avere dei pacchetti di componenti solo per certi ambienti (es. solo Blazor, solo gli ambienti desktop, solo mobile maui+flutter, ecc.) per poter offrire prezzi più bassi, ma ripeto presumo che siano strade già esplorate e se hanno scelto “l’all-in” di 1800+ componenti e 16 librerie avranno le loro ragioni.

Conclusioni

Ero molto curioso di provare a fondo questa libreria per capire veramente se il prezzo fosse consono alla qualità offerta. La risposta è sicuramente affermativa se consideriamo, come dicevo innanzi, non solo il prodotto vero e proprio, ma anche il livello di supporto e di documentazione offerto. È ovvio che il progetto dove si usa deve essere bello grosso per poterne sostenere i costi, ma se il budget lo permette, non ho nessuna difficoltà a consigliarne l’acquisto e l’uso.

Aggiungi Commento

Copyright © 1997-2024 Sandro Rizzetto | All Rights Reserved | Riproduzione delle fotografie vietata | Powered by me