Gli UserControl sono indubbiamente una gran bella invenzione in ASP.NET, per qualche verso anche meglio dei WebControl per i progetti low-end, perchè consentono di creare delle componenti riutilizzabili con molta più facilità risparmiando molto tempo. Con l'introduzione delle webparts poi il loro utilizzo si è moltiplicato a dismisura. Tuttavia non è la prima volta che mi trovo ad avere degli UserControl che pur essendo riutilizzabili come auspicabile talvolta soffrono di alcuni fastidiosi vincoli imposti ad esempio dalla navigazione del website.

Se ad esempio pensiamo ad un controllo che rappresenti la form di creazione/modifica di una entità del nostro sistema, non è sempre detto che alla pressione del tasto salva il comportamento debba essere il medesimo. Poniamo che il controllo sia usato una volta come "inserimento rapido" - posizionato immediatamente sotto ad una gridview - mentre un'altra volta verrà inserito in una pagina autonoma per l'edit dell'entità stessa. Se nel primo caso alla pressione del tasto Salva ci dovremmo aspettare di rimanere nella stessa pagina per consentire l'inserimento di un'altro record, nel secondo potremmo attenderci di tornare alla pagina da cui siamo arrivati. Se inseriamo questo comportamento hard-coded nello UserControl stiamo indubbiamente limitando la riutilizzabilità del controllo stesso. Dovremmo perciò gestire una serie di eventi per fare in modo che la navigazione non abbia impatto sulla riutilizzabilità del controllo.

Recentemente ho adottato un sistema interessante che mi aiuta a gestire in modo più rapido questa problematica. Il primo passo è quello di creare uno UserControl base per tutti i controlli che dovranno implementare questo tipo di navigazione:

   1: public class CoreUserControl : UserControl
   2: {
   3:     /// <summary>
   4:     /// Gets or sets the navigations.
   5:     /// </summary>
   6:     /// <value>The navigations.</value>
   7:     [PersistenceMode(PersistenceMode.InnerProperty)]
   8:     public NavigationCollection Navigations
   9:     {
  10:        get { return GetViewState<NavigationCollection>("navigations", new NavigationCollection()); }
  11:        set { SetViewState<NavigationCollection>("navigations", value); }
  12:     }
  13:     
  14:     /// <summary>
  15:     /// Navigates to.
  16:     /// </summary>
  17:     /// <param name="navigationName">Name of the navigation.</param>
  18:     protected void NavigateTo(string navigationName, params object [] args)
  19:     {
  20:        string navigation = this.Navigations.GetNavigationUrl(navigationName, args);
  21:     
  22:        if (!string.IsNullOrEmpty(navigation))
  23:            Response.Redirect(navigation);
  24:     }
  25: }

Come si vede il controllo espone una collection di oggetti di tipo Navigation che rappresentano appunto le possibili transizioni in base agli eventi generati dallo usercontrol. Nel caso del controllo di cui sopra potrebbero essere OnSaved e OnCancel per rappresentare appunto la navigazione successiva al salvataggio dell'entità e quella causata dalla pressione di Cancel. L'oggetto Navigation espone solamente due proprietà: Name e NavigationUrlFormat. Il primo è il nome che daremo all'evento che causa la transizione mentre il secondo è l'url di destinazione comprensivo di eventuali marcatori per parametri che siano inseriti a runtime. Ecco un esempio di configurazione:

   1: <uc:PropertyForm runat="server" id="editProperty" Title="<%$ Resources:common,EditProperty_Title %>">
   2:     <Navigations>
   3:         <uc:Navigation Name="OnSaved" NavigationUrlFormat="~/list.aspx?id={0}" />
   4:         <uc:Navigation Name="OnCancel" NavigationUrlFormat="~/home.aspx" />
   5:     </Navigations>
   6: </uc:PropertyForm>

Lo usercontrol, perciò al termine di ogni operazioe dovrà comportarsi come segue:

1) Verifica che sia presente una Transizione con il nome richiesto

2) Se la transizione esiste attiva la navigazione verso la destinazione

3) Se la transizione non esiste rimane sulla pagina stessa

Questa verifica è fatta dal metodo NavigateTo(), esposto dallo UserControl base. Grazie ad esso, all'interno del codice del controllo sarà sufficiente scrivere il seguente codice per gestire la navigazione:

   1: protected void thisForm_ItemInserted(object sender, FormViewInsertedEventArgs e)
   2: {
   3:     if (e.Exception != null)
   4:         e.ExceptionHandled = HandleException(e.Exception);
   5:     else
   6:     {
   7:         NavigateTo("OnSaved", this.CurrentClass);
   8:     }
   9:  
  10:     e.KeepInInsertMode = true;
  11: }

Naturalmente non è l'unico modo: ad esempio potremmo usare l'url prodotto da GetNavigationUrl() per alimentare un link in una gridview e fare così in modo che si apra la form relativa ad una riga presenti in essa.

Personalmente ho trovato il sistema da un lato abbastanza flessibile e dall'altro sufficientemente semplice da non richiedere complesse infrastrutture che alla fine complicano le cose molto più di quello che semplificano.

Technorati tags: , ,

Aggiungi Commento