Freeteo


Pensieri e C#dice di Matteo Raumer

Estendere un oggetto con proprietà dinamiche e binding in Silverlight

Quando mi trovo a parlare con altri sviluppatori, la prima cosa che consiglio è definire il meglio possibile un buon Domain Model dell'applicazione, in termini di Classi, Funzionalità,Comportamenti e Architettura dell'applicazione, per avere dei benefici durante lo sviluppo e l'inevitabile "ondata" di richieste successive all'analisi...

Per quanto riguarda la definizione degli oggetti .net ci mette a disposizione dei tool fantastici Entity Framework, LinqToSql , adesso con Visual Studio 2010 anche diagrammi UML o semplicemente il Class Designer. A volte però per necessità di "personalizzazione" o cmq se vogliamo dare una "dinamicità spinta" dell'applicazione, non si riesce a definire un oggetto completo di tutte le proprietà che possono servire...alcune possono dover essere gestite  in fase di configurazione o di funzionamento, perchè dipendono dall'esigenza "verticale" dell'utilizzatore.

In questa situazione c'è bisogno di un oggetto che permetta questo dinamismo, le 2 tecniche che mi sono trovato ad usare sono state:

Dotarlo di una Collection di un oggetto che identificherà un campo del database (il cosiddetto "CampoDinamico") per cui una proprietà "List<CampoDinamico>" che poi da codice viene letta|scritta da codice:
    public class CampoDinamico
    {
        public string Nome { getset; }
        public string Alias { getset; }
        public object Valore { getset; }         ...     }
    public class Utente
    {
        ...
        public List<CampoDinamico> CampiDinamici { getset; }
    }
I controlli che visualizzano i dati, ad esempio le griglie diventano "dinamici" nel senso che si aspettano la presenza di questa collection e vanno in discovery di questi campi, ad esempio le query sul database poi vengono generate dinamicamente in base a questi.
La comodità di questa tecnica è che si conosce a priori il tipo "CampoDinamico" quindi diventa più facile estenderlo con le ulteriori proprietà che possono essere utile (ReadOnly, Identity etc...)
Di contro abbiamo il fatto che il codice si complica un po' nel senso che devo accedere a quella proprietà e il binding di componenti diventa difficile se non si usa WPF...


La seconda tecnica, e a mio avviso forse anche la migliore, è l'Extender, ossia dare la possibilità di definire delle proprietà a runtime tramite Dictionary<string,object> in cui la stringa corrisponde al nome della proprietà, e invece quello che torna è il valore (chiaramente in object per avere ancora maggiore flessibilità):
    public class Utente
    {
        public int ID { getset; }
        public string Descrizione { getset; }


        private Dictionary<stringobject> proprieta = new Dictionary<stringobject>();

        public object this[string nome]
        {
            get {
                if (proprieta.ContainsKey(nome))
                    return proprieta[nome];
                else
                    return null;
            }

            set {
                if (proprieta.ContainsKey(nome))
                    proprieta[nome] = value;
                else
                    proprieta.Add(nome, value);
            }
        }
        //--- per enumerare
        public IEnumerable<string> Keys { get { return proprieta.Keys; } }
    }

Anche qui c'è bisogno di un codice che faccia il discovery, ma diventa leggermente più semplice, infatti portando fuori la proprietà "Keys" del mio Dictionary sottostante, basta un semplice foreach:
   //--- discovery di che proprietà ha l'oggetto
   Utente utente = utenti.First();
   foreach (string chiave in utente.Keys)
   {
....

La cosa simpatica è che Silverlight supporta il binding per questa tecnica, ossia possiamo dire di agganciarsi a quella proprietà definendone il nome tra parentesi quadre "[NomeProprieta]":
<ListBox x:Name="listBox" Margin="16,43,216,93">
    <ListBox.ItemTemplate>
        <DataTemplate>
        <StackPanel>
            <TextBlock Text="{Binding [codice]}" />
            <TextBlock Text="{Binding [eta],FallbackValue=-}" />
            <TextBlock Text="{Binding ID}" />
            <TextBlock Text="{Binding Descrizione}" />
        </StackPanel>
    </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>
(Notare che è disponibile anche la proprietà "FallbackValue" che sta a significare "se non riesci a fare il binding, visualizza questo valore")

Anche qui posso generare una griglia dinamica, ed associare il Binding con le parentesi quadre:
   //--- aggiungo le colonne
   Utente ut = utenti.First();
   foreach (var k in ut.Keys)
   {
       utentiGrid.Columns.Add(new DataGridTextColumn() {     
                                   Binding = new Binding("[" + k + "]"),
                                   Header = k,
                                   Width = DataGridLength.Auto
                               });
                                       
   }
   
   //--- bindo la collection
   utenteGrid.ItemsSource = utenti;

A mio avviso le proprietà dinamiche degli oggetti non sono esigenze che si verificano in ogni progetto, ma se qualche cliente ce lo chiede, 
almeno sappiamo che è fattibile abbastanza facilmente...in Silverlight poi è anche utilizzabile nel meccanismo di Binding.
Categoria: Tips
martedì, 27 apr 2010 Ore. 10.36

Messaggi collegati






  • Views Home Page: 213.117
  • Views Posts: 368.088
  • Views Gallerie: 426.160
  • n° Posts: 163
  • n° Commenti: 148
Anno 2014

Anno 2013

Anno 2012

Anno 2011

Anno 2010

Anno 2009

Anno 2008

Anno 2007

Anno 2006

Anno 2005
Copyright © 2002-2007 - Blogs 2.0
dotNetHell.it | Home Page Blogs
ASP.NET 2.0 Windows 2003