Condividi tramite


Capitolo 5: Associazione dati

 

Introduzione
Capitolo 1: Modello di applicazione "Longhorn"
Capitolo 2: Creazione di un'applicazione "Longhorn"
Capitolo 3: Controlli e XAML
Capitolo 4: Archiviazione

Capitolo 5: Associazione dati

Brent Rettore
Wise Owl Consulting

Febbraio 2004

Contenuto

Creazione di un data binding
Tipi di data binding
Convertitori
Invio di notifiche di modifica delle proprietà
Riepilogo

Il data binding nel suo senso tradizionale significa associare alcuni dati sottostanti a uno o più elementi dell'interfaccia utente. I dati forniscono le informazioni da visualizzare. Gli elementi dell'interfaccia utente eseguono il rendering delle informazioni nel formato appropriato.

"Longhorn" estende l'idea tradizionale del data binding in diversi modi. È possibile associare una proprietà di un elemento dell'interfaccia utente a una proprietà di qualsiasi oggetto CLR (Common Language Runtime) o a un attributo di un nodo XML.

Il data binding può essere unidirezionale (in entrambe le direzioni) o bidirezionale. Ad esempio, il data binding tradizionale contiene le informazioni nel flusso dell'origine dati all'elemento dell'interfaccia utente associato. In alternativa, le informazioni nell'elemento dell'interfaccia utente possono tornare all'origine dati. Il data binding bidirezionale, naturalmente, supporta il flusso di informazioni in ogni direzione e consente all'input dell'utente tramite l'elemento dell'interfaccia utente di aggiornare i dati nell'origine dati.

Il data binding può anche essere statico (una sola volta) o dinamico. Con il data binding statico, il trasferimento delle informazioni si verifica quando si crea inizialmente il data binding. Le modifiche successive ai valori nei dati non influiscono sul valore nell'elemento dell'interfaccia utente. Il data binding dinamico consente di modificare i dati nell'origine dati per propagarsi all'elemento Interfaccia utente e viceversa.

Il data binding "Longhorn" supporta anche la trasformazione dei dati durante il flusso da e verso gli elementi dell'origine dati e dell'interfaccia utente. Questa trasformazione consente all'autore dell'applicazione di aggiungere semantica dell'interfaccia utente ai dati.

Alcune trasformazioni tipiche potrebbero essere le seguenti:

  • Visualizzazione di numeri negativi in numeri rossi e positivi in nero
  • Visualizzazione di immagini basate su un contatto online o offline
  • Creazione di grafici a barre dinamici associando l'altezza di un rettangolo a un prezzo azionario
  • Animazione della posizione di un'immagine associandone le coordinate a una proprietà di un oggetto CLR

Anche il data binding "Longhorn" è fondamentalmente asincrono. Un elemento dell'interfaccia utente riceve un evento quando una nuova origine dati viene associata all'elemento . Inoltre, poiché un'origine dati raccoglie i dati, genera eventi per indicare che il relativo contenuto è stato modificato.

È possibile associare dati a qualsiasi oggetto CLR o XMLnode e quindi è possibile eseguire facilmente l'associazione dei dati a vari modelli di dati in "Longhorn": oggetti CLR, XML, ADO.NET Set di dati, messaggi del servizio Web o oggetti WinFS. "Longhorn" offre anche una serie di classi di origine dati predefinite che consentono di inserire i dati in modo semplice e dichiarativo in modo asincrono in un'applicazione. Sono disponibili origini dati specifiche per oggetti XML, .NET, ADO.NET set di dati e oggetti WinFS. Il modello di origine dati è estendibile, quindi è possibile creare classi di origine dati personalizzate quando necessario.

Creazione di un data binding

È possibile associare una proprietà dinamica di un elemento dell'interfaccia utente a una proprietà di qualsiasi oggetto CLR. A tale scopo, è necessario descrivere la corrispondenza desiderata tra un elemento di un'origine dati e l'elemento dell'interfaccia utente di destinazione. Ogni corrispondenza o associazione di questo tipo deve specificare quanto segue:

  • Elemento dell'origine dati
  • Percorso del valore appropriato nell'elemento dell'origine dati
  • Elemento dell'interfaccia utente di destinazione
  • Proprietà appropriata dell'elemento dell'interfaccia utente di destinazione

Associazione dati

Framework rappresenta un data binding da un'istanza della classe MSAvalon.Data.Bind . Questa classe ha una serie di proprietà che controllano il data binding: Path, BindType, UpdateType, Transformer, Culture, BindFlags e Source.

Impostare la proprietà Path su una stringa che specifica la proprietà o il valore nell'origine dati a cui viene associato l'oggetto bind. La proprietà BindType controlla la direzione e la frequenza dell'associazione dati. Deve essere uno dei tre valori: OneWay, TwoWay e OneTime. Un tipo di associazione OneWay fa sì che il data binding trasferisca nuovi valori dall'origine dati alla proprietà di destinazione, ma non propaga le modifiche nella proprietà di destinazione all'origine dati. Un tipo di associazione TwoWay propaga le modifiche in entrambe le direzioni. Quando si specifica il tipo di associazione OneTime , il data binding trasferisce il valore dall'origine dati alla proprietà di destinazione solo quando si attiva per la prima volta l'associazione.

È possibile impostare la proprietà Transformer su qualsiasi oggetto che implementa l'interfaccia IDataTransformer . Quando il data binding propaga un valore, passa il valore attraverso il trasformatore. Il trasformatore esamina il valore in ingresso e produce un nuovo valore come output. Si noti che i valori di input e output non devono essere dello stesso tipo. È possibile avere un flag integer come input e produrre file di immagine diversi come output.

La proprietà UpdateType determina quando le modifiche apportate alla proprietà di destinazione vengono propagate all'origine dati quando il tipo di associazione è TwoWay. È possibile specificare uno dei tre valori: immediate significa propagare il nuovo valore all'origine dati immediatamente dopo la modifica della proprietà di destinazione; OnLostFocus significa propagare il valore quando il controllo di destinazione perde lo stato attivo dell'input; e Explicit indica di attendere che il codice chiami l'oggetto bind e lo indichi per propagare il nuovo valore.

La proprietà Source fa riferimento all'elemento dati di origine dell'associazione. È possibile utilizzare gli attributi DataSource, ElementSource, DataContextSource o ObjectSource per impostare la proprietà Source dell'oggetto bind. Usare l'attributo ElementSource per impostare Source su un elemento specificando l'ID elemento come valore dell'attributo ElementSource . L'attributo DataContextSource consente di impostare Source sul contesto dati di un altro elemento impostando l'ID elemento su DataContextSource. Usare l'attributo ObjectSource per specificare un oggetto come origine dell'associazione. Infine, l'attributo DataSource consente di impostare la proprietà Source sulla proprietà Data di DataSource. Questa operazione verrà descritta in dettaglio nella sezione Elemento origine dati.

La proprietà Culture consente di specificare cultureInfo per le associazioni che devono essere consapevoli delle impostazioni cultura.

La proprietà BindFlags supporta un singolo valore diverso da zero: NotifyOnTransfer. È molto importante comprendere che un data binding è intrinsecamente asincrono. Quando si modifica il valore nell'origine dati, la proprietà di destinazione corrispondente non riceve immediatamente il valore aggiornato. Potrebbe essere necessario un periodo di tempo arbitrario prima che il nuovo valore venga propagato alla proprietà di destinazione. Quando è necessario sapere quando l'associazione ha completato l'aggiornamento della proprietà di destinazione, impostare la proprietà BindFlags sul valore NotifyOnTransfer . Il data binding attiverà quindi l'evento MSAvalon.Data.DataTransfer dopo l'aggiornamento della proprietà di destinazione.

Definizione di un'espressione di associazione tramite codice

È possibile creare un data binding a livello di codice, anche se si prevede che raramente sia necessario o si voglia farlo. È sufficiente creare un'istanza della classe Bind e chiamare il metodo SetBinding. Ecco un esempio possibile:

using MSAvalon.Data;

Bind binding = new Bind ();
binding.Path = path;
binding.BindType = bindType;
binding.Source = source;
binding.UpdateType = updateType;

element.SetBinding (property, binding);

In alternativa, ecco un altro modo per scrivere il codice precedente usando uno dei costruttori pratici della classe Bind:

using MSAvalon.Data;

Bind binding = new Bind (path, bindType, source, updateType);
element.SetBinding (property, binding);

È possibile usare altri metodi pratici, ad esempio il metodo SetBinding in un elemento, e semplificare il codice precedente a questo:

element.SetBinding (property, path, bindType, source, updateType);

Definizione di un'espressione di associazione tramite markup

Si prevede che si preferisca definire la maggior parte dei data binding usando il markup. Tutti i concetti precedenti vengono comunque applicati, ovvero si crea un oggetto Bind , si impostano le relative proprietà sui valori appropriati e lo si associa a una proprietà di un elemento di destinazione. Ad esempio, il markup seguente crea un oggetto Bind come valore della proprietà Text dell'oggetto Button.

<DockPanel xmlns="https://schemas.microsoft.com/2003/xaml" />
  <DockPanel.Resources>
     <myNameSpace:Person def:Name="MyPerson" Name="Bob"/>
  </DockPanel.Resources> . . .
  <Button>
    <Button.Content>
      <Bind Path="Name" BindType="OneWay" ObjectSource="{MyPerson}" />
    </Button.Content>
  </Button>

Per associare un data binding alla proprietà di un particolare elemento dell'interfaccia utente, usare il data binding come valore della proprietà . Nell'esempio appena illustrato, il data binding associa la risorsa denominata MyPerson alla proprietà Text dell'elemento Button perché ho definito il data binding tra i tag di inizio e fine Button.Text .

La proprietà DockPanel Resources dichiara che gli elementi figlio seguenti sono risorse. A differenza degli elementi XAML normali, di cui viene creata un'istanza quando il runtime analizza il file XAML, il runtime non crea un'istanza di una risorsa finché non viene effettivamente usata.

Nell'esempio precedente, l'origine delle associazioni è un oggetto Person , pertanto l'istanza bind fa riferimento a questa istanza dell'oggetto Person .

L'attributo Path specifica il percorso all'interno dell'elemento dell'origine dati al valore di interesse. Nell'esempio precedente, il percorso è semplicemente Name, quindi l'associazione recupera la proprietà Name dell'istanza Person . Tuttavia, il percorso potrebbe essere più complesso. Ad esempio, se la proprietà Name ha restituito un oggetto con una struttura aggiuntiva, il percorso potrebbe essere simile a Name.FirstName.

Nell'esempio precedente è stato illustrato come definire un data binding usando una definizione di proprietà complessa per il valore della proprietà Button.Text . Tuttavia, è possibile usare un'alternativa e notevolmente più compatta, definizione per un'espressione di data binding. In questo caso, si definisce una stringa come espressione di associazione dati. La stringa inizia con un carattere asterisco, che il compilatore XAML interpreta come carattere di escape, quindi il nome della classe per creare un'istanza e quindi, racchiuso tra parentesi, una serie di coppie di valori dei nomi delimitati da punti e virgola.

<DockPanel >
  §
 <Button Text="*Bind(Path=Name;BindType=OneWay)" />
  §
</DockPanel>

Quando si definisce un data binding, ma non si specifica un valore per la proprietà Source (usando DataSource, ElementSource, DataContextSource o ObjectSource), il data binding recupera l'origine dati dalla proprietà DataContext per l'elemento corrente. Quando l'elemento corrente non dispone di DataContext, l'oggetto binding recupera in modo ricorsivo il dataContext dell'elemento padre. In questo modo è possibile definire un'origine dati una sola volta sull'elemento appropriato nel markup e quindi usare tale origine dati in varie associazioni sugli elementi figlio.

Nell'esempio seguente viene impostata la proprietà DataContext dell'elemento DockPanel su un data binding che fa riferimento all'origine dati. In modo efficace, tutti gli elementi figlio ereditano questa proprietà DataContext quando non lo impostano su un valore diverso. Poiché i data binding negli elementi Button non specificano un valore per la proprietà Source , l'associazione usa l'origine da DataContext ereditata. Naturalmente, è sempre possibile specificare un'origine per causare l'uso di un'origine dati specifica.

<DockPanel xmlns="http:////schemas.microsoft.com//2003//xaml//"
           DataContext="{MyPerson}>
  §    <Button Text='*Bind(Path="Name";BindType="OneWay")' />
    <Button Text='*Bind(Path="Age";BindType="OneWay")' />
 §</DockPanel>

Tipi di data binding

Un particolare data binding può essere di tre tipi: OneTime, OneWay e TwoWay. Impostare la proprietà BindType su uno dei valori enumerati quando si dichiara l'associazione.

One-Time data binding

Quando si richiede un'associazione dati una volta, il runtime, usando l'origine dati e il percorso specificato, recupera il valore di origine e inizializza la proprietà di destinazione specificata a tale valore. In genere, nulla accade successivamente quando l'origine o il valore di modifica della proprietà di destinazione.

Tuttavia, esistono due casi speciali. Quando il DataContext di un elemento cambia, in modo efficace, l'origine dati è stata modificata e quindi l'associazione esegue un altro trasferimento una volta. Inoltre, in molti casi, il contesto dei dati fa riferimento a una raccolta di oggetti. Quando l'oggetto corrente per una raccolta viene modificato, il data binding esegue un trasferimento one-time.

One-Way data binding

Quando si richiede un data binding unidirezionale, il runtime recupera il valore di origine e inizializza la proprietà di destinazione specificata a tale valore. Ogni volta che il valore di origine modifica il data binding recupera il nuovo valore e reinizializza la proprietà di destinazione.

Two-Way data binding

Quando si richiede il data binding bidirezionale, il runtime recupera il valore di origine e inizializza la proprietà di destinazione specificata a tale valore. Ogni volta che il valore di origine cambia, il data binding recupera il nuovo valore e reinizializza la proprietà di destinazione. Inoltre, quando la proprietà di destinazione cambia valore, ad esempio quando l'utente digita in un controllo di modifica, il data binding recupera il nuovo valore della proprietà di destinazione e lo propaga nuovamente all'origine. Il data binding bidirezionale è il tipo predefinito di un data binding.

Convertitori

Un trasformatore consente di convertire un valore da una maschera a un'altra man mano che si propaga a e da un'origine dati a una destinazione. È possibile usare un trasformatore per convertire un valore dalla relativa rappresentazione interna a un valore visualizzato univoco. Ad esempio, è possibile usare un trasformatore per visualizzare un numero a virgola mobile negativa usando il testo rosso e un numero positivo usando il testo nero. È anche possibile visualizzare icone diverse per varie valutazioni degne di credito per un cliente.

È anche possibile usare un trasformatore come convertitore di tipi di dati. Ad esempio, il valore di origine potrebbe essere un oggetto Point , mentre la proprietà a cui si vuole associare il valore richiede un'istanza Length.

Un trasformatore riceve anche le informazioni cultura per l'interfaccia utente come uno dei relativi parametri. È possibile usare queste informazioni per personalizzare l'interfaccia utente presentata alle impostazioni cultura correnti dell'utente, ad esempio è possibile fornire icone diverse durante l'esecuzione in impostazioni cultura diverse.

Interfaccia IDataTransformer

Un trasformatore è qualsiasi oggetto che implementa l'interfaccia IDataTransformer . Ecco la definizione dell'interfaccia:

interface IDataTransformer {
  object Transform (object o, DependencyID id, CultureInfo culture);
  object InverseTransform (object o, PropertyInfo pInfo, CultureInfo culture);
}

Un data binding chiama il metodo Transform durante la propagazione di un valore di origine a una proprietà di destinazione. Il parametro o è il valore di origine, l'ID parametro identifica la proprietà di destinazione e le impostazioni cultura dei parametri identificano le impostazioni cultura per la trasformazione.

Il data binding chiama il metodo InverseTransform durante la propagazione di un valore della proprietà di destinazione modificato nuovamente all'origine. In questo caso, il parametro o è il valore della proprietà di destinazione modificato e pInfo identifica il tipo in cui convertire il valore. Come prima, le impostazioni cultura sono le impostazioni cultura per la trasformazione.

Entrambi i metodi consentono di restituire null per indicare che l'associazione non deve propagare un valore nella rispettiva direzione. Ecco un semplice trasformatore che restituisce un colore basato su un valore integer:

<SimpleText Text="*Bind(Path=Name)" Foreground="*Bind(Path=Age; Transformer=AgeToColorTransformer)"/>

public class AgeToColorTransformer: IDataTransformer {
  public object Transform (object o, DependencyID di, CultureInfo culture) {
    int age = (int) o;
    if (age < 0 || age > 120) return Grey;
    if (age <= 30) return Green;
    if (age <= 70) return Gold;
    if (age <= 120) return Red;
  }
  public object InverseTransform (object o, PropertyInfo i, CultureInfo c) {
        return null;
  }
}

Invio di notifiche di modifica delle proprietà

CLR non fornisce un modo generico per un oggetto di notificare ai client che una delle relative proprietà è stata modificata. Tuttavia, un'associazione dinamica richiede tali notifiche in modo che l'associazione possa propagare i valori delle proprietà modificati alla proprietà dinamica di destinazione. "Longhorn" introduce l'interfaccia IPropertyChange per consentire a un oggetto di segnalare quando una delle relative proprietà modifica il valore. Si noti che l'interfaccia definisce un singolo evento di tipo PropertyChangedEventHandler e che il gestore eventi può recuperare il nome della proprietà modificata usando la proprietà PropertyName del secondo parametro al gestore.

interface IPropertyChange {
  event PropertyChangedEventHandler PropertyChanged;
}

delegate void PropertyChangedEventHandler (object sender, 
                                           PropertyChangedEventArgs e);

class PropertyChangedEventArgs : EventArgs {
  public virtual string PropertyName { get ;}
}

Nel codice seguente è stata riscritta la classe Person precedente nel capitolo per supportare la modifica delle proprietà Name e Age e per generare gli eventi appropriati quando si verificano tali modifiche.

namespace MyNamespace {
  public class Person : IPropertyChange {
    private string m_name;
    private int    m_age;
    public event PropertyChangedEventHandler PropertyChanged;

    public string Name {
      get { return m_name; }
      set {
        if (m_name != value) {
          m_name = value;
          RaisePropertyChangeEvent ("Name");
        }
      }
    }
    public int Age {
      get { return m_age; }
      set {
        if (m_age != value) {
          m_age = value;
          RaisePropertyChangeEvent ("Age");
        }
      }
    }

    private void RaisePropertyChangedEvent (string propertyName) {
      if (PropertyChanged != null)
        PropertyChanged (this, new PropertyChangedEventArgs (propertyName));
    }
    
    public Person (string name, int age) {
      m_name = name; m_age = age;
    }
  }
}

L'oggetto implementa questa interfaccia chiamando il delegato PropertyChanged ogni volta che una delle relative proprietà "interessanti" modifica il valore. Si noti che è necessario richiamare il delegato solo quando una proprietà utilizzata in un valore di associazione dinamica cambia valore. L'oggetto può avere proprietà per cui non si attivano notifiche di modifica.

Per motivi di prestazioni, è consigliabile attivare le notifiche di modifica solo quando la proprietà ha effettivamente modificato il valore. Quando l'oggetto non conosce il valore modificato della proprietà, può richiedere l'aggiornamento di tutte le associazioni a qualsiasi proprietà su se stessa oppure può passare String.Empty per il nome della proprietà modificato.

Elemento origine dati

"Longhorn" offre un set di origini dati predefinite, che consente di ottenere facilmente e dichiarativamente i dati nell'applicazione in modo asincrono e senza bloccare l'interfaccia utente.

Un elemento dell'origine dati è qualsiasi oggetto che implementa l'interfaccia IDataSource .

interface IDataSource {
        public virtual Object Data { get; }
        public virtual void Refresh()
}

Questa interfaccia ha una proprietà Data che consente all'associazione di ottenere i dati dall'elemento dell'origine dati. Il metodo Refresh consente all'associazione di richiedere che l'elemento dell'origine dati recupera i dati quando non è disponibile. "Longhorn" fornisce una serie di classi di origine dati e alcune di esse verranno visualizzate brevemente.

In genere, un'implementazione dell'origine dati fornisce anche una proprietà fortemente tipizzata che restituisce l'API nativa del provider di dati. Ad esempio, le classi SqlDataSource e XmlDataSource forniscono rispettivamente le proprietà DataSet e Document:

class SqlDataSource : IDataSource, … {
   §    DataSet           DataSet { get; }
    §}
class XmlDataSource : IDataSource, … {
    §    XmlDocument       Document { get; }
    §}

Pertanto, se è davvero necessario, è possibile accedere direttamente al provider di dati sottostante.

Uso di qualsiasi oggetto CLR come origine dati

La classe ObjectDataSource consente di creare un'istanza di un tipo specificato come elemento di origine dati. In genere si userà XAML e si dichiarano le origini dati come risorse nel markup. Si supponga, ad esempio, di avere la definizione seguente di una classe Person in un assembly denominato MyAssembly e che si vuole usare un'istanza di questa classe come elemento di origine dati:

namespace MyNamespace {
  public class Person {
    private string m_name;
    private int m_age;

    public string Name { get { return m_name; } }
    public int Age { get { return m_age; } }

    public Person (string name, int age) {
      m_name = name; m_age = age;
    }
  }
}

La classe Person non richiede alcun supporto aggiuntivo per essere un elemento di origine dati. È possibile usare un'istanza della classe ObjectDataSource come elemento dell'origine dati e informarlo che il provider di dati sottostante deve essere un'istanza della classe Person . A tale scopo, è possibile usare il markup per dichiarare un'istanza di ObjectDataSource come risorsa XAML.

<DockPanel>
  <DockPanel.Resources>
    <ObjectDataSource def:Name ="source1"
       TypeName="MyNamespace.Person, MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0123456789abcde f"
       Parameters="Brent, 0x30" />
  </DockPanel.Resources>
</DockPanel>

Come sempre, i nomi degli elementi XAML rappresentano nomi di classe Framework. Pertanto, l'elemento ObjectDataSource indica di creare un'istanza della classe ObjectDataSource . Il valore dell'attributo def:Name è il nome di questa risorsa ("source1" nell'esempio precedente).

L'istanza ObjectDataSource creerà una nuova istanza della classe a cui fa riferimento TypeName chiamando il costruttore predefinito o, quando si specifica l'attributo Parameters , chiamando il costruttore che corrisponde meglio alla firma del valore dell'attributo Parameter .

Tenere presente che il markup è equivalente al codice, quindi il markup precedente è uguale al codice seguente:

ObjectDataSource source1 = new ObjectDataSource();
source1.TypeName = "MyNamespace.Person, MyAssembly, Version=1.0.0.0,   
                    Culture=neutral, PublicKeyToken=0123456789abcdef";
source1.Parameters = "Brent, 0x30";

La classe ObjectDataSource fornisce anche meccanismi per chiamare metodi sugli oggetti e fare riferimento a oggetti esistenti oltre a creare semplicemente un'istanza di un nuovo oggetto.

Uso di un'origine dati con data binding

È possibile dichiarare un'origine dati come risorsa nella proprietà Resources di un elemento o delle risorse a livello di applicazione. Qualsiasi origine dati dichiarata nelle risorse dell'applicazione può essere usata nell'applicazione in qualsiasi pagina. Un'origine dati definita nelle risorse di un elemento può essere usata solo nell'ambito dell'elemento.

È possibile dichiarare un'origine dati come risorsa nella proprietà Resources di un elemento o delle risorse a livello di applicazione. Qualsiasi origine dati dichiarata nelle risorse dell'applicazione può essere usata nell'applicazione in qualsiasi pagina. Un'origine dati definita nelle risorse di un elemento può essere usata solo nell'ambito dell'elemento.

Nell'esempio appena illustrato, il data binding associa l'origine dati denominata source1. È possibile impostare l'attributo DataSource sull'ID risorsa di una risorsa XAML. Quando la risorsa implementa l'interfaccia IDataSource, il runtime imposta la proprietà Sourcedell'istanza bind sull'oggetto restituito dalla proprietà Data della risorsa DataSource specificata. Quando la risorsa non implementa l'interfaccia IDataSource , il runtime imposta la proprietà Source dell'associazione all'oggetto risorsa stessa.

Nell'esempio precedente l'attributo DataSource fa riferimento a una risorsa ObjectDataSource . Pertanto, l'associazione richiede la proprietà Data da ObjectDataSource. L'origine dati, a sua volta, crea un'istanza della classe Person come specificato nel markup.

Nel primo pulsante, la proprietà Source dell'istanza bind fa riferimento a questa istanza dell'oggetto Person . Il percorso è semplicemente Name, quindi l'associazione recupera la proprietà Name dell'istanza Person .

Nel secondo pulsante , DataContext è associato all'oggetto ObjectDataSource. Questa azione imposta DataContext dell'oggetto Button sull'oggetto Person in modo che qualsiasi associazione su Button userà l'oggetto Person come origine predefinita per le associazioni.

È possibile associare dati in modo analogo a una qualsiasi delle origini dati disponibili. Alcune delle altre origini dati fornite con "Longhorn" sono menzionate nei paragrafi che seguono. Altri, ad esempio le origini dati per ottenere i dati dai servizi Web, saranno disponibili online.

Uso di XML come origine dati

La classe XmlDataSource è un'origine dati che usa un dom (Document Object Model) XML come provider di dati sottostante. È possibile usare il markup per creare il DOM da un URL (Uniform Resource Locator) che fa riferimento a un flusso XML. È anche possibile creare il DOM fornendo il codice XML inline con il markup come illustrato nell'esempio seguente:

Uso dell'URI

<DockPanel>
  <DockPanel.Resources>
    <XmlDataSource def:Name="source2"
       Source="http://www.wiseowl.com/People.xml"
       XPath="/People/Person[@Age>21]" />

Uso del markup inline

    <XmlDataSource def:Nsme="source3"
       XPath="/People/Person[@Age>50]" >
       <People>
           <Person Name='Bambi' Age='61'>
           <Person Name='Bozo' Age='54'>
           <Person Name='Brent' Age='48'>
           §       </People>
    </XmlDataSource>
</DockPanel.Resources> 
</DockPanel>

Uso di un dataset come origine dati

La classe SqlDataSource è un'origine dati che usa un DataSet come provider di dati sottostante. Crea un oggetto DataSet e lo riempie eseguendo un comando SQL nel database.

<DockPanel>
  <DockPanel.Resources>
    <SqlDataSource def:Name="source4">
      ConnectionString="server=localhost;Database=UserGroup"
       SelectCommand="SELECT * FROM Members" />
    </SqlDataSource>
  <DockPanel.Resources> 
</DockPanel>

In alternativa, è possibile usare la classe ObjectDataSource e associare a una classe derivata da DataSet fortemente tipizzata definita in un file code-behind.

<DockPanel>
  <DockPanel.Resources >
  <ObjectDataSource def:Name="sds1"
    Type="MyDataset"/>
  </ObjectDataSource>
 </DockPanel.Resources>
</DockPanel>

Uso di Archiviazione di Windows come origine dati

La classe WinFS DataSource usa WinFS come provider di dati sottostante. È possibile usarlo per associare alle informazioni quotidiane gestite da Microsoft® Windows® Storage.

<DockPanel>
  <DockPanel.Resources>
    <WinFSDataSource ContextString="c:\">
      <WinFSDataSource.Query 
    Type="Person" Filter="DisplayName='Ted'" Sort="DisplayName ASC">
        <Query.ProjectionOptions Field="DisplayName" />
        <Query.ProjectionOptions Field="Birthdate">
          <Projection.ProjectionOptions … />
        </Query.ProjectionOptions>
      </ WinFSDataSource.Query>
    </WinFSDataSource>
  </DockPanel.Resources>
</DockPanel>

Uso di un'origine dati personalizzata

È anche possibile specificare una classe personalizzata come origine dati. La classe deve implementare l'interfaccia IDataSource . In genere si vuole associare un prefisso dello spazio dei nomi XML allo spazio dei nomi della classe personalizzata e quindi usare il nome della classe qualificata dal prefisso nel markup come di consueto:

<Canvas … >
  §   
  <Canvas.Resources>
    <WO:InfraredDataSource def:Name="source8"
       PropA='value1'
       PropB='value2'
    </WO:InfraredDataSource>
  </Canvas.Resources>
</Canvas>

Riepilogo

Il data binding offre un metodo semplice ed efficiente per connettere le informazioni a un elemento dell'interfaccia utente che visualizza i dati. Si ottiene la propagazione automatica dei valori in direzione, una volta o ripetutamente, con la possibilità di convertire la rappresentazione dei dati al momento della necessità. È possibile eseguire questa operazione con codice a livello di codice poco o senza codice usando il markup. Il data binding consente di ottenere i dati in cui si vuole e passare alla scrittura del resto dell'applicazione.

Continuare con il capitolo 6: Comunicazione