in

dotNet Umbria

Il primo User Group in Umbria sul mondo .Net

Articoli

Articoli vari degli iscritti a DotNetUmbria

ObjectDataProvider e databinding su WPF

Tramite WPF è possibile istanziare in diversi modi un oggetto da utilizzare come sorgente dati per il databinding.
Nel precedente post "Ancora databinding su WPF" si è visto come (attraverso le risorse della classe Window - Window.Resources) è possibile  dichiarare un oggetto come risorsa statica, e, grazie al tag x:key, qualsiasi controllo è in grado di referenziarlo come sorgente dati, permettendo all'engine di WPF di istanziare l'oggetto richiamando il suo costruttore base.

In alcuni scenari, nei quali non si vuole perdere l'approccio dichiarativo messo a disposizione da XAML, ma che richiedono comportamenti particolari, come il richiamo di costruttori specializzati o metodi con parametri dell'oggetto, WPF fornice la classe ObjectDataProvider.Questa Classe non fa altro che incapsulare la risorsa statica e fornire gli strumenti per interoperare con essa.

Riprendiamo la configurazione precedente della risorsa statica mySource che referenziava la classe mySource scritta in c#

<Window.Resources>

       <local:mySource x:Key="mySource"/>

</Window.Resources>

Per incapsulare la risorsa basta aggiungere

<Window.Resources>

         <local:mySource x:Key="mySource"/>
         <ObjectDataProvider x:Key="dataProvider"  ObjectType="{x:Type local:mySource}"/>

</Window.Resources>

Dal codice precedente si vede subito che anche l'ObjectDataProvaider è stato definito come risorsa statica, e che può essere referenziato grazie alla sua chiave dataProvider, definita attraverso il tag x:Key.
A questo punto  si può effettuare il binding attraverso l'ObjectDataProvider, che si occuperà di istanziare la risorsa mySource che sta incapsulando.
L'esempio del precedente post diventa così

<ListView ItemsSource="{Binding Source={StaticResource dataProvider}}">

Da notare che l'applicazione continua a funzionare come in precedenza.
Fino ad ora non abbiamo visto nulla di interessante, infatti per vedere le potenzialità di questo oggetto dobbiamo fare qualche modifica alla nostra classe sorgente dati, aggiungendo un secondo costruttore che accetta un parametro di tipo int e un metodo che accetta anche'esso un parametro di tipo int.

public class mySource : ObservableCollection<mySourceItem>
{
    public mySource()
   {
    }

    //Nuovo costruttore che accetta un parametro int, rappresentante il numero di item da construire
    public mySource(int param)
   {
       for (int i = 0; i <= param; i++)
      {
          this.Add(new mySourceItem("Customer"+i.ToString(), "Customer"+i.ToString()+" Description"));
       }   
    }
  
  //Metodo che inizializza una nuova classe mySource con un numero di item definito dal paramtro param
    public mySource GetItems(int param)
    {

       mySource _mySourse = new mySource();
       for (int i = 0; i <= param; i++)
       {

          _mySourse.Add(new mySourceItem("Customer" + i.ToString(),
           "Customer" + i.ToString() + " Description"));
       }
       return _mySourse;
    }

}

Benché non ha molto senso creare un metodo che realizzi una nuova istanza della stessa classe, è stato aggiunto solo per facilitare questo esempio.

Utilizzando la proprietà CostructorParameters dell' ObjectDataProvider  che accetta una collezione di oggetti, possiamo stabilire quale costruttore prendere attraverso la firma dei suo parametri.

L'esempio diventa:

<Window.Resources>
        <ObjectDataProvider x:Key="dataProvider" ObjectType="{x:Type local:mySource}">
            <ObjectDataProvider.ConstructorParameters>
                <sys:Int32>4</sys:Int32>
            </ObjectDataProvider.ConstructorParameters>
        </ObjectDataProvider>
</Window.Resources>

Ogni parametro è referenziato con il suo tipo, in questo caso Int32, perciò sul nodo root di Window bisogna aggiungere il namespace dei tipi base del Framework; nota che la chiave sys è puramente arbitraria e può essere cambiata a proprio piacimento.

xmlns:sys="clr-namespace:System;assembly=mscorlib"

Se mandiamo in esecuzione il programma si noterà che il nostro ListView è costituito da quattro Item, proprio perché ha utilizzato il costruttore custom, seguendo la sequenza dei parametri, passandogli il numero 4.

Analogamente l'ObjectDataProvider ci fornisce la possibilità di chiamare un metodo della classe che incapsula al suo interno , utilizzando la proprietà MethodName e passandogli  i propri parametri grazie alla proprietà MethodParameters  che accetta una collezione di oggetti.
L'esempio precedente diventa

<Window.Resources>
        <ObjectDataProvider x:Key="dataProvider" ObjectType="{x:Type local:mySource}" MethodName="GetItems">
          <ObjectDataProvider.MethodParameters>
              <sys:Int32>4</sys:Int32>
           </ObjectDataProvider.MethodParameters>
       </ObjectDataProvider>
</Window.Resources>

Potete scaricare la soluzione d'esempio realizzata con Visual Studio 2008 :
ODPDemo.zip

 

Only published comments... Feb 20 2008, 10:54 PM by matteo
Filed under: ,
Attachment: ODPDemo.zip

Comments

 

Alberto said:

Sempre + illuminante.

Se ho ben capito, un'approccio professionale in wpf, sarebbe quello di usare il binding con ObjectDataProvider e scrivendo i metodi (typename) nella classe businness esterna. Un po' come con objectdatasource in asp.net?

(chiedo scusa eventualmente per la banalità)

Grazie infinite...

Alberto Paganuzzi

February 27, 2008 6:25 PM
 

matteo said:

In realtà non c'è un approccio più professionale di un altro.

WPF fornisce molte funzionalità in XAML, che andremo ad illustrare con il tempo, per mantenere un approccio dichiarativo.

E' chiaro che per tutti quegli scenari, nei quali non è semplice ricondurre il tutto in XAML, l'approccio procedurale rimane la  soluzione vincente.

Infatti senza dover per forza scrivere da codice tutto il binding, si può semplicemente fornire la sorgente dati , utilizzando la proprietà DataContext di un qualsiasi oggetto definito in XAML.

Partendo dal presupposto che tutto quello che si può fare in XAML si può fare da codice, la scelta di un puro approccio dichiarativo in XAML, o un approccio procedurale da codice o un mix di entrambi dipende essenzialmente dallo scenario che incontriamo.

March 1, 2008 10:45 AM
 

dardino said:

dove posso trovare un'esempio di come leggere e scrivere i dati in un database con il semplice binding dei controlli WPF?

sono riuscito a trovare esempi solo per il binding da sorgente dati a controlli WFP...

come facci a fare il viceversa?

in particolare io uso LINQ to SQL tramite il tool che crea file dbml. approccio decisamente molto comodo. per il momento io riesco a caricare e rileggere gli elementi modificati e salvarli sul database solo da codice c# ma vorrei poterlo fare con il databinding che mi sembra di aver capito che si tratta di uno strumento piuttosto potente.

posso bindarmi direttamente a LINQ  o devo per forza crearmi una classe apposita?

come posso creare form padre-figlio in WPF con il databind?

Grazie

May 19, 2008 3:50 PM
dotNet Umbria 2007-2008
Powered by Community Server (Commercial Edition), by Telligent Systems