Costruzione di custom controls con supporto a design time: Property Editor e Component Editor

di Stefano Mostarda, in ASP.NET,

Nel precedente articolo abbiamo visto alcune tecniche per migliorare la visualizzazione di controlli nel designer, in questo secondo mi concentrerò invece su come realizzare degli editor personalizzati di proprietà e di controllo, che rende l'uso dei controlli molto più veloce ed il loro look più professionale.

Come esempio creeremo un controllo con 4 proprietà:

  • Text
  • Height
  • Width
  • Date

Il controllo renderizza un tag DIV con il testo e la data al proprio interno e dalle dimensioni specificate attraverso le rispettive proprietà. Il testo deve essere formattato separando le parole con il carattere ";". Vedremo come creare un editor per formattare la proprietà Text, uno per settare la data ed uno per settare le altre proprietà.

Per comodità, nell'articolo verrà usato l'acronimo PE (Property Editor) per identificare l'editor di proprietà.

Editor personalizzati di proprietà (UITypeEditor)

Gli UITypeEditor sono degli editor creati ad-hoc per settare una particolare proprietà. Questo meccanismo è utile per velocizzare il processo di valorizzazione o perché difficile o perché, addirittura, impossibile tramite PE. Esistono 2 tipi di editor:

  • Il primo utilizza una form. VS.NET ce ne fornisce alcune di default come la form per selezionare un url o un'immagine, o quella per riempire gli Items di una DropDownList.
  • Il secondo utilizza un controllo che viene visualizzato direttamente nel PE. Anche qui VS.NET fornisce già alcuni esempi come il controllo per selezionare un colore.

VS.NET utilizza il seguente schema per implementare questa feature. Quando viene selezionato un componente sul designer, il PE scorre le proprietà e ne cerca l'attributo Editor . Quando ne incontra una con questo attributo valorizzato, utilizza la classe in esso specificata, chiamandone il metodo GetEditStyle per ottenere il tipo di bottone da far vedere sulla destra della proprietà selezionata. Quando l'utente clicca sul bottone, viene chiamato il metodo EditValue che istanzia e visualizza l'editor personalizzato, e, infine, setta il nuovo valore della proprietà.

Procediamo per passi

Nel caso si voglia creare un editor utilizzando una form, per prima cosa bisogna creare la WindowsForm. Aggiungiamo un costruttore che accetta in input il valore della proprietà da settare cosi da poter già inizializzare i campi. In questo caso viene passato il testo che poi viene splittato ed inserito in una ListBox.

public  TextEditorForm(string AValore) : this(){
   lxElementi.Items.AddRange(AValore.Split(';'));
   CaricaTesto();
  }

Quando l'utente chiude la form confermando i dati inseriti, la proprietà che torna il nuovo valore viene settata. Nel caso si voglia usare un controllo, al posto di una form, questo step va saltato.

Successivamente si deve creare la classe che fa da collegamento tra la proprietà e l'editor (sia form che controllo). La classe deve avere alcune importanti caratteristiche: ereditare da System.Drawing.Design. UITypeEditor , eseguire l'override dei metodi GetEditStyle e EditValue . Il metodo GetEditStyle serve a specificare al PE quale tipo di bottone viene visualizzato sulla destra della proprietà quando questa è selezionata. Il valore di ritorno è un'enumerazione che può avere tre valori:

  • Modal: viene visualizzata una elisse e quando cliccata viene aperta la form in modale;
  • li>DropDown: viene visualizzato un bottone stile DropDown e viene visualizzato un controllo dentro il PE non in modale;
  • None: valore di default, non mostra nulla.

EditValue è il metodo che viene invocato quando l'utente clicca sul bottone. Questo metodo prende un riferimento al servizio che permette la creazione di editor personalizzati e, se questo viene correttamente tornato, viene usato per visualizzare l'editor. In caso di form, questa viene prima istanziata e poi visualizzata utilizzando il metodo ShowDialog . Se l'utente ha confermato le modifiche viene usata la proprietà della form che torna il nuovo valore.

Public class TextEditorBridge : System.Drawing.Design.UITypeEditor {

  public override object  EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) {

  IWindowsFormsEditorService edSvc = null;
  if (context != null && context.Instance != null && provider != null){
      edSvc =  (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
     }
     if (edSvc != null)  {
      TextEditorForm fm = new TextEditorForm(Convert.ToString(value));
      if (edSvc.ShowDialog(fm) == DialogResult.OK)
                    return fm.ReturnText;
     }

     return value;
   }

   public override UITypeEditorEditStyle  GetEditStyle(ITypeDescriptorContext context) {
     if (context != null && context.Instance != null) {
      return UITypeEditorEditStyle.Modal;
     }
     return  base.GetEditStyle(context);
   }
  }
  

Nel caso invece si voglia creare un controllo nel PE, la faccenda è leggermente diversa perché bisogna creare il controllo da codice e poi passarlo in input al metodo DropDownControl del servizio. Una volta selezionata la data, all'evento "DateSelected" del MonthCalendar viene chiamato il metodo CloseDropDown del servizio per chiudere l'editor.

  public class DateEditorBridge : System.Drawing.Design.UITypeEditor {

  
  IWindowsFormsEditorService edSvc = null;
   MonthCalendar Calendar;
   public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) {
     string szDate;

     if (context != null && context.Instance != null && provider != null) {
      edSvc =(IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
     }

     if (edSvc != null){
      Calendar = new MonthCalendar();
      try{
        Calendar.DateSelected += new DateRangeEventHandler(OnDateRange);
        Calendar.ShowToday = false;
        Calendar.ShowTodayCircle = true;
        edSvc.DropDownControl(Calendar);
        return Calendar.SelectionEnd.ToString();
      }
      catch{
        return value;
      }
      finally{
        Calendar.Dispose();
      }
     }
     return value;
   }

   public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) {
     if (context != null && context.Instance != null) {
      return UITypeEditorEditStyle.DropDown;
     }
     return base.GetEditStyle(context);
   }

   private void OnDateRange(object  sender, DateRangeEventArgs e){
     if (edSvc != null)  edSvc.CloseDropDown();
   }
  } 

L'ultimo passo da completare è il collegamento tra la proprietà e la classe "ponte". Questo avviene tramite i famosi attributi ed in particolare l'attributo Editor :

Editor(typeof(SMDivCompEditorBridge), typeof(ComponentEditor))

Il primo parametro rappresenta il tipo della form, mentre il secondo il tipo base della classe ponte.

Questa immagine mostra il bottone accanto alla proprietà per richiamare l'editor:

Questa mostra la form per editare la proprietà.

Questa mostra il l'editor nel PE in azione

2 pagine in totale: 1 2

Attenzione: Questo articolo contiene un allegato.

Contenuti dell'articolo

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti