data binding Windows Presentation Foundation: parte 1

 

Shawn Wildermuth

Maggio 2006

Si applica a:
   Microsoft Windows Presentation Foundation

Riepilogo: Illustra come usare il data binding basato su XAML per eseguire la manipolazione dei dati nei progetti di Microsoft Windows Presentation Foundation. (16 pagine stampate)

Contenuto

Introduzione
Associazioni XAML, semplificate
Dove siamo?
Riferimenti

Introduzione

Microsoft Windows Presentation Foundation (WPF; in precedenza Avalon) introduce un nuovo modo profondo per sviluppare interfacce utente per i client avanzati. Per la prima volta, WPF separa la progettazione dell'interfaccia utente dal codice. Questa separazione significa che, come ASP.NET, il markup si trova in genere in un file, mentre il codice si trova in un altro. Questa separazione esiste solo in fase di compilazione. Il file di markup viene usato per generare codice sposato con il file di codice per produrre l'applicazione.

Per facilitare la progettazione, Microsoft ha sviluppato un linguaggio di markup avanzato denominato XAML. XAML è un linguaggio di markup basato su XML che supporta un nuovo modello per lo sviluppo di applicazioni con supporto nativo per molti concetti di interfaccia utente diversi, ad esempio disegno 2D e 3D, animazioni, contenimento dei controlli, controllo e flusso di documenti, nonché un modello di data binding avanzato. Questo articolo offre una panoramica del data binding WPF. Questo articolo presuppone che si abbia una certa conoscenza di WPF. In caso contrario, vedere l'articolo Guida di Hitchhiker di Time Sneath a WPF Beta 1 per una panoramica.

Perché usare il data binding?

Se si inizia a usare WPF, ci si potrebbe chiedere se è più facile evitare l'apprendimento del data binding e scrivere semplicemente codice per eseguire la maggior parte della manipolazione dei dati nei progetti. Anche se questo potrebbe essere un modo valido per farlo, sospetto che si creerà da usare, e forse anche amare il data binding basato su XAML. Di seguito è riportato un piccolo esempio.

La figura 1 mostra l'interfaccia utente per un semplice progetto WPF. È un editor per un feed RSS, per consentire agli utenti di visualizzare e modificare i feed.

Fare clic qui per un'immagine più grande Fare clic qui

Figura 1. Editor RSS (fare clic sull'immagine per un'immagine più grande)

Il layout dell'editor è piuttosto semplice, come illustrato di seguito nel codice XAML seguente.

<Window x:Class="ExampleCS.Window1"
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    Title="ExampleCS"
    Loaded="Window1_Loaded"
    >
  <StackPanel>
    <TextBlock HorizontalAlignment="Center" 
          FontWeight="Bold">
      BlogEditor
    </TextBlock>
    <StackPanel Orientation="Horizontal" 
           HorizontalAlignment="Center">
      <ListBox Name="entryListBox" 
          Height="300" 
          SelectionChanged="entryListBox_Changed"/>
      <Grid Width="500" Margin="5">
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="50" />
          <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
          <RowDefinition Height="25" />
          <RowDefinition Height="25" />
          <RowDefinition Height="25" />
          <RowDefinition Height="*" />
          <RowDefinition Height="25" />
        </Grid.RowDefinitions>
        <TextBlock Grid.Row="0" Grid.Column="0">Title:</TextBlock>
        <TextBox Grid.Row="0" Grid.Column="1" Name="titleText" />
        <TextBlock Grid.Row="1" Grid.Column="0">Url:</TextBlock>
        <TextBox Grid.Row="1" Grid.Column="1" Name="urlText" />
        <TextBlock Grid.Row="2" Grid.Column="0">Date:</TextBlock>
        <TextBox Grid.Row="2" Grid.Column="1" Name="dateText" />
        <TextBlock Grid.Row="3" Grid.Column="0">Body:</TextBlock>
        <TextBox Grid.Row="3" Grid.Column="1" 
            Name="bodyText" 
            TextWrapping="Wrap" />
        <Button Grid.Row="4" 
                  Grid.ColumnSpan="2" 
                  Grid.Column="1"
            Click="updateButton_Click">
          Update
        </Button>
      </Grid>
    </StackPanel>
  </StackPanel>
</Window>

Prendere nota dei gestori eventi in grassetto. In questo modo si verificherà la maggior parte del codice, per caricare il feed RSS e compilare i controlli WPF.

C#

XmlDocument blog = new XmlDocument();
const string BLOGURL = @"z:\adoguy.RSS";

public Window1()
{
  InitializeComponent();
  blog.Load(BLOGURL);
}

void Window1_Loaded(object sender, RoutedEventArgs e) 
{
  FillListBox();
}

void FillListBox()
{
  entryListBox.Items.Clear();

  XmlNodeList nodes = blog.SelectNodes("//item");
  foreach (XmlNode node in nodes)
  {
    ListBoxItem item = new ListBoxItem();
    item.Tag = node;
    item.Content = node["title"].InnerText;
    entryListBox.Items.Add(item);
  }
}

Visual Basic .NET

  Dim blog As New XmlDocument
  Const BLOGURL As String = "z:\adoguy.RSS"

  Public Sub New()
    InitializeComponent()
    blog.Load(BLOGURL)
  End Sub

  Sub Window1_Loaded(ByVal sender As Object, _
                     ByVal e As RoutedEventArgs) 
    FillListBox()

  End Sub

  Sub FillListBox()

    entryListBox.Items.Clear()

    Dim nodes As XmlNodeList = blog.SelectNodes("//item")

    For Each node As XmlNode In nodes

      Dim item As New ListBoxItem
      item.Tag = node
      item.Content = node("title").InnerText
      entryListBox.Items.Add(item)

    Next

  End Sub

In questo codice è possibile visualizzare il caricamento di un documento XML con il feed RSS e la compilazione di ListBox con i titoli di tutte le voci.

Successivamente, sarà necessario gestire ciò che accade quando viene effettuata una selezione in ListBox.

C#

void entryListBox_Changed(object sender, RoutedEventArgs e)
{
  if (entryListBox.SelectedIndex != -1)
  {
    XmlNode node = ((ListBoxItem)entryListBox.SelectedItem).Tag as XmlNode;
    if (node != null)
    {
      titleText.Text = node["title"].InnerText;
      urlText.Text = node["guid"].InnerText;
      dateText.Text = node["pubDate"].InnerText;
      bodyText.Text = node["description"].InnerText;
    }
  }
}

Visual Basic .NET

  Sub entryListBox_Changed(ByVal sender As Object, _
                           ByVal e As SelectionChangedEventArgs) 

    If entryListBox.SelectedIndex <> -1 Then

      Dim node As XmlNode = CType(entryListBox.SelectedItem, ListBoxItem).Tag
      If Not node Is Nothing Then

        titleText.Text = node("title").InnerText
        urlText.Text = node("guid").InnerText
        dateText.Text = node("pubDate").InnerText
        bodyText.Text = node("description").InnerText

      End If

    End If

  End Sub

Quando il controllo ListBox viene modificato, viene compilato il controllo TextBoxes con l'elemento del feed RSS selezionato. A questo scopo, si ottiene il testo interno dell'elemento del feed. Si noti che è anche necessario conservare una copia del nodo con ListBoxItem ed eseguire un po' di cast per ottenere in ogni gestore eventi.

Infine, è necessario gestire ciò che accade quando si fa clic sul pulsante Aggiorna .

C#

void updateButton_Click(object sender, RoutedEventArgs e)
{
  if (entryListBox.SelectedIndex != -1)
  {
    XmlNode node = ((ListBoxItem)entryListBox.SelectedItem).Tag as XmlNode;
    if (node != null)
    {
      node["title"].InnerText = titleText.Text;
      node["guid"].InnerText = urlText.Text;
      node["pubDate"].InnerText = dateText.Text;
      node["description"].InnerText = bodyText.Text;

      blog.Save(BLOGURL);

      FillListBox();
    }
  }
}

Visual Basic .NET

  Sub updateButton_Click(ByVal sender As Object, _
                         ByVal e As RoutedEventArgs)

    If entryListBox.SelectedIndex <> -1 Then

      Dim node As XmlNode = CType(entryListBox.SelectedItem, ListBoxItem).Tag

      If Not node Is Nothing Then

        node("title").InnerText = titleText.Text
        node("guid").InnerText = urlText.Text
        node("pubDate").InnerText = dateText.Text
        node("description").InnerText = bodyText.Text

        blog.Save(BLOGURL)

        FillListBox()

      End If

    End If

  End Sub

In questo caso, si aggiornano i nodi con le nuove informazioni, si salva il documento XML e si fa in modo che listBox venga riempito, nel caso in cui il titolo sia stato modificato. Anche se si tratta di una semplice applicazione, il codice necessario è un po'esteso. Potrebbe essere più semplice con i data binding XAML? Sì, potrebbe essere. Di seguito è riportato il codice XAML dello stesso progetto, usando i data binding XAML.

<StackPanel 
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  >
  <StackPanel.Resources>
    <XmlDataProvider x:Key="RssFeed" Source="z:\adoguy.RSS" />
  </StackPanel.Resources>
  <TextBlock HorizontalAlignment="Center" 
      FontWeight="Bold">
    Blog Editor
  </TextBlock>
  <StackPanel Orientation="Horizontal" 
    HorizontalAlignment="Center">
    <ListBox Name="entryListBox" 
        Height="300" 
        ItemsSource="{Binding Source={StaticResource RssFeed}, XPath=//item}"
    >
      <ListBox.ItemTemplate>
        <DataTemplate>
          <TextBlock Text="{Binding XPath=title}" />
        </DataTemplate>
      </ListBox.ItemTemplate>
    </ListBox>
    <Grid Width="500" 
        Margin="5" 
        DataContext="{Binding ElementName=entryListBox, Path=SelectedItem}" >
      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="50" />
        <ColumnDefinition Width="*" />
      </Grid.ColumnDefinitions>
      <Grid.RowDefinitions>
        <RowDefinition Height="25" />
        <RowDefinition Height="25" />
        <RowDefinition Height="25" />
        <RowDefinition Height="*" />
        <RowDefinition Height="25" />
      </Grid.RowDefinitions>
      <TextBlock Grid.Row="0" Grid.Column="0">Title:</TextBlock>
      <TextBox Grid.Row="0" Grid.Column="1" 
          Name="titleText" 
          Text="{Binding XPath=title}" />
      <TextBlock Grid.Row="1" Grid.Column="0">Url:</TextBlock>
      <TextBox Grid.Row="1" Grid.Column="1" 
          Name="urlText" 
          Text="{Binding XPath=guid}" />
      <TextBlock Grid.Row="2" Grid.Column="0">Date:</TextBlock>
      <TextBox Grid.Row="2" Grid.Column="1" 
          Name="dateText" 
          Text="{Binding XPath=pubDate}" />
      <TextBlock Grid.Row="3" Grid.Column="0">Body:</TextBlock>
      <TextBox Grid.Row="3" Grid.Column="1" 
          Name="bodyText" 
          TextWrapping="Wrap" 
          Text="{Binding XPath=description}" />
      <Button Grid.Row="4" Grid.ColumnSpan="2" Grid.Column="1" >
          Update
      </Button>
    </Grid>
  </StackPanel>
</StackPanel>

Questo codice XAML funziona senza code-behind. La figura 2 mostra l'applicazione che usa solo XAML (usando XAMLPad).

Fare clic qui per un'immagine più grande Fare clic qui

Figura 2. Editor RSS in XAMLPad (fare clic sull'immagine per un'immagine più grande)

Ci si potrebbe chiedere: "Come può funzionare?" Funziona perché viene usata l'associazione XAML per eseguire gran parte del lavoro per noi. Anche se ognuna delle tecniche nel codice XAML viene descritta più avanti in dettaglio, verranno illustrate le parti del data binding, per spiegare in realtà come funziona questa operazione.

Prima di tutto, viene creato un oggetto XmlDataProvider in cui caricare e gestire il documento XML per l'editor.

<XmlDataProvider x:Key="RssFeed" Source="z:\adoguy.RSS" />

Questo indica al codice XAML di caricare un documento XML dall'unità Z: per compilare il modulo.

Successivamente, viene associato listBox.

<ListBox Name="entryListBox" 
        Height="300" 
        ItemsSource="{Binding Source={StaticResource RssFeed}, XPath=//item}"
    >

Ciò indica alla casella di riepilogo di trovare la risorsa nel codice XAML denominato RssFeed e di usarla come origine dati. Inoltre, indica alla casella di riepilogo di ottenere l'elenco di elementi a cui eseguire l'associazione dall'espressione XPath (in questo caso, tutti gli elementi dell'elemento nel documento).

Specificare quindi cosa visualizzare negli elementi della casella di riepilogo specificando il modello di dati.

<DataTemplate>
  <TextBlock Text="{Binding XPath=title}" />
</DataTemplate>

Indica a ListBox di creare un oggetto TextBlock per ogni elemento e di utilizzare XPath per determinare cosa visualizzare in TextBlock.

Successivamente, associamo la griglia che contiene tutti i dettagli.

<Grid Width="500" 
        Margin="5" 
        DataContext="{Binding ElementName=entryListBox, Path=SelectedItem}" >

In questo caso viene detto al codice XAML di associare il contenitore (in questo caso grid) all'elemento selezionato di ListBox. Viene usato ElementName anziché Source, perché si vuole eseguire l'associazione a un controllo nel documento XAML, anziché ad alcuni dati esterni. Impostando DataContext, tutti i controlli all'interno di Grid verranno impostati sullo stesso oggetto (in questo caso SelectedItem).

A questo punto, ogni controllo TextBox viene associato alla parte del documento XML necessario.

<TextBlock Grid.Row="0" Grid.Column="0">Title:</TextBlock>
      <TextBox Grid.Row="0" Grid.Column="1" 
          Name="titleText" 
          Text="{Binding XPath=title}" />
      <TextBlock Grid.Row="1" Grid.Column="0">Url:</TextBlock>
      <TextBox Grid.Row="1" Grid.Column="1" 
          Name="urlText" 
          Text="{Binding XPath=guid}" />
      <TextBlock Grid.Row="2" Grid.Column="0">Date:</TextBlock>
      <TextBox Grid.Row="2" Grid.Column="1" 
          Name="dateText" 
          Text="{Binding XPath=pubDate}" />
      <TextBlock Grid.Row="3" Grid.Column="0">Body:</TextBlock>
      <TextBox Grid.Row="3" Grid.Column="1" 
          Name="bodyText" 
          TextWrapping="Wrap" 
          Text="{Binding XPath=description}" />

Poiché DataContext è già stato impostato, è possibile specificare semplicemente l'espressione XPath per ottenere le parti dei feed RSS necessari.

Questo è molto da cercare di ingoiare in un singolo gulp. Smettila e prendi un respiro. Non mi aspetto che tu lo faccia in uno sgobbo caduto. Nella sezione seguente ho suddiviso molte delle idee che hai visto nell'esempio precedente in bit più gestibili.

Associazioni XAML, semplificate

Per iniziare con un semplice esempio del funzionamento dell'oggetto Binding , esaminiamo il documento XAML molto semplice seguente.

<Window 
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  >
  <Canvas>
    <TextBox Text="This is a TextBox" />
    <TextBlock Canvas.Top="25" >Test</TextBlock>
  </Canvas>
</Window>

In questo modo viene creato un'area di disegno semplice con i due controlli, come illustrato nella figura 3.

Aa480224.wpfdatabinding_pt103(en-us,MSDN.10).gif

Figura 3. Un'area di disegno XAML semplice

È possibile associare TextBlock per visualizzare il testo del controllo TextBox durante la digitazione. A tale scopo, è necessario un oggetto Binding per collegare i due oggetti insieme. La prima cosa da fare consiste nell'aggiungere un nome al controllo TextBox, in modo che sia possibile farvi riferimento in base al nome dell'elemento.

<TextBox Name="theTextBox" />

Successivamente, è necessario aggiungere un binding all'elemento TextBlock di TextBlock.

<TextBlock Canvas.Top="25">
  <TextBlock.Text>    <Binding ElementName="theTextBox" Path="Text" />  </TextBlock.Text>
</TextBlock>

In questo modo, il testo di TextBlock deve essere impostato come tipo utente nel controlloTextBox.

L'inserimento di tutti questi risultati restituisce il codice seguente.

<Window 
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  >
  <Canvas>
    <TextBox Name="theTextBox" Text="Hello" />
    <TextBlock Canvas.Top="25">
      <TextBlock.Text>
        <Binding ElementName="theTextBox" Path="Text" />
      </TextBlock.Text>
    </TextBlock>
  </Canvas>
</Window>

Questo codice XAML crea un modulo che modifica textBlock durante la digitazione nel controllo TextBox, come illustrato nella figura 4.

Aa480224.wpfdatabinding_pt104(en-us,MSDN.10).gif

Figura 4. Controllo associato

Congratulazioni: hai il tuo primo binding! Ma la sintassi XML è un po' dettagliata. Dovrebbe esserci un modo migliore per scriverlo.

Uso dell'associazione abbreviata

Nell'esempio precedente è stato illustrato come creare il data binding aggiungendo elementi Binding alle proprietà. In questo semplice esempio, non sembra troppo oneroso eseguire il data binding in questo modo; Tuttavia, man mano che i documenti XAML aumentano, è probabile che questa sintassi dettagliata diventi complessa. Per risolvere questo problema, XAML supporta una versione abbreviata della sintassi di associazione.

Ad esempio, usando la mano breve, l'esempio precedente sarà simile al seguente.

<Window 
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  >
  <Canvas>
    <TextBox Name="theTextBox" Text="Hello" />
    <TextBlock Canvas.Top="25"
               Text="{Binding ElementName=theTextBox, Path=Text}" />
  </Canvas>
</Window>

La sintassi shorthand è racchiusa tra parentesi graffe ({}), inizia con la parola Binding e contiene coppie nome/valore per gli attributi dell'associazione. Lo scopo della sintassi a breve è abilitare il data binding con meno sequenze di tasti e maggiore leggibilità. Per il resto di questo articolo, sto usando la sintassi a mano breve.

Origini di associazione

Fino a questo punto, è stato usato un altro controllo come origine per tutti gli esempi di associazione. Nella maggior parte dei progetti basati su XAML, tuttavia, l'associazione a origini diverse da altri controlli. La chiave per la maggior parte del data binding è la proprietà Source . Negli esempi precedenti viene usata la proprietà ElementName , usata per eseguire il binding a un controllo, anziché usare la proprietà Source . Per la maggior parte delle applicazioni, si vuole associare a origini più significative, ad esempio oggetti XML o .NET. XAML supporta questa operazione con gli oggetti provider di dati. Esistono due tipi di provider di dati incorporati in XAML: ObjectDataProvider e XmlDataProvider. ObjectDataProvider viene usato per l'associazione da e verso oggetti .NET e, non sorprendentemente, viene usato xmlDataProvider per l'associazione a e da frammenti e documenti XML. È possibile specificare un provider di dati nella sezione risorse di qualsiasi contenitore XAML.

Uso di XmlDataProvider

Di seguito è riportato un esempio che usa l'oggetto XmlDataProvider .

<StackPanel 
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  >
  <StackPanel.Resources>
    <XmlDataProvider x:Key="FavoriteColors">      <x:XData>        <Colors >          <Color>Blue</Color>           <Color>Black</Color>           <Color>Green</Color>           <Color>Red</Color>         </Colors>      </x:XData>    </XmlDataProvider>
  </StackPanel.Resources>
  <TextBlock HorizontalAlignment="Center" 
             FontWeight="Bold">
    XML Example
  </TextBlock>
  <ListBox Width="200" Height="300" 
           ItemsSource="{Binding Source={StaticResource FavoriteColors},            XPath=/Colors/Color}">
  </ListBox>
</StackPanel>

Nelle risorse di StackPanel è disponibile un oggetto XmlDataProvider . X :Key indica il nome da usare per farvi riferimento negli oggetti Binding . All'interno del provider è stato creato xml inline per l'uso come origine del data binding. Per usare i dati inline, è necessario circondarlo con un elemento XData , come illustrato nel codice. Nell'associazione per ListBox è stato specificato il provider come origine dell'associazione. Quando un'origine dati si trova nel documento XAML, è necessario specificare che l'oggetto è una risorsa statica, come illustrato nel codice. Infine, viene usata un'istruzione XPath per specificare quale raccolta all'interno del documento XML deve essere usata per riempire ListBox. Questo codice genera il modulo illustrato nella figura 5.

Aa480224.wpfdatabinding_pt105(en-us,MSDN.10).gifAa480224.wpfdatabinding_pt105(en-us,MSDN.10)

Figura 5. Data binding XML

In alternativa, è possibile specificare che il provider usa un percorso o un URL per trovare l'origine del codice XML per creare lo stesso modulo, specificando l'attributo Source di XmlDataProvider.

<XmlDataProvider x:Key="FavoriteColors" 
                 Source="D:\Writing\msdn\avalondatabindingpt1\xaml\colors.xml"
/>

L'attributo Source di XmlDataProvider può anche puntare agli URL standard, per consentire di creare un accesso rapido alle API XML, ad esempio RSS.

<StackPanel 
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  >
  <StackPanel.Resources>
    <XmlDataProvider x:Key="MyRSS" 
      Source="http://adoguy.com/RSS"
    />
  </StackPanel.Resources>
  <TextBlock HorizontalAlignment="Center" 
             FontWeight="Bold">
    XML Example
  </TextBlock>
  <ListBox Width="500" Height="300" 
           ItemsSource="{Binding Source={StaticResource MyRSS}, 
           XPath=//item/title}">
  </ListBox>
</StackPanel>

Chiamando un feed RSS, è possibile creare una pagina che elenca rapidamente gli argomenti del mio blog in un listBox, come illustrato nella figura 6.

Aa480224.wpfdatabinding_pt106(en-us,MSDN.10).gifAa480224.wpfdatabinding_pt106(en-us,MSDN.10)

Figura 6. Elenco degli argomenti del mio blog

Uso di ObjectDataProvider

È necessario eseguire l'associazione agli oggetti .NET. Questo è il luogo in cui viene fornito ObjectDataProvider . Questo provider di dati consente di creare associazioni per i tipi di dati .NET.

Ad esempio, è possibile creare una semplice raccolta di stringhe in .NET, come indicato di seguito.

public class MyStrings : List<String>
{
  public MyStrings()
  {
    this.Add("Hello");
    this.Add("Goodbye");
    this.Add("Heya");
    this.Add("Cya");
  }
}

–oppure–

Public Class MyStrings
  Inherits List(Of String)

  Public Sub New()
    Me.Add("Hello")
    Me.Add("Goodbye")
    Me.Add("Heya")
    Me.Add("Cya")
  End Sub

End Class

È anche possibile usare un'istruzione di elaborazione nel documento XAML per aggiungere un intero spazio dei nomi degli oggetti CLR ai tipi supportati del documento specificando lo spazio dei nomi come dichiarazione xmlns . Ad esempio, è possibile eseguire il mapping di classi di un intero spazio dei nomi nel codice XAML, come indicato di seguito.

<Window 
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    Title="Simple Source Binding"
    xmlns:local="clr-namespace:XamlExamples"
    x:Class="XamlExamples.SimpleSource"
 >
  <!-- ... -->
</Window>

Per importare classi da un assembly esterno, è possibile specificare una dichiarazione xmlns , ma specificare il nome dell'assembly, come indicato di seguito.

<Window 
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    Title="Simple Source Binding"
    xmlns:sys="clr-namespace:System,assembly=mscorlib"
    x:Class="XamlExamples.SimpleSource"
 >
  <!-- ... -->
</Window>

Dopo aver importato i tipi, è possibile usare ObjectDataProvider per specificare un'origine dati da uno di questi tipi.

<Window 
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    Title="Simple Source Binding"
    xmlns:local="clr-namespace:XamlExamples"
    x:Class="XamlExamples.SimpleSource"
 >
  <Window.Resources>
    <ObjectDataProvider x:Key="MyStringData"                         ObjectType="{x:Type local:MyStrings}" />
  </Window.Resources>  
    <StackPanel>
      <TextBlock HorizontalAlignment="Center" 
               FontWeight="Bold">
      Simple Source Example
    </TextBlock>
    <ListBox Name="theListBox" Width="200" Height="300" 
      ItemsSource="{Binding Source={StaticResource MyStringData}}"/>
  </StackPanel>
</Window>

È anche possibile creare la risorsa specificando un elemento XAML con il nome dello spazio dei nomi e il tipo da usare, come indicato di seguito.

<Window 
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    Title="Simple Source Binding"
    xmlns:local="clr-namespace:XamlExamples"
    x:Class="XamlExamples.SimpleSource"
 >
  <Window.Resources>
    <local:MyStrings x:Key="MyStringData" />
  </Window.Resources>  
    <StackPanel>
      <TextBlock HorizontalAlignment="Center" 
               FontWeight="Bold">
      Simple Source Example
    </TextBlock>
    <ListBox Name="theListBox" Width="200" Height="300" 
      ItemsSource="{Binding Source={StaticResource MyStringData}}"/>
  </StackPanel>
</Window>

Questa sintassi funziona esattamente come ObjectDataSource, ma è un po 'più semplice da usare. Ora che lo spazio dei nomi viene importato, è possibile aggiungere una risorsa che fa riferimento alla classe di origine dati specificando il nome della classe , ad esempio MyStrings. Il data binding è identico agli esempi precedenti, perché il codice XAML non interessa il tipo di origine dati, solo che è un'origine dati.

Modalità di binding

Nella maggior parte dei casi, si vuole che l'associazione sia un'associazione bidirezionale. L'oggetto Binding supporta diverse modalità per supportare i casi d'uso delle differenze, come illustrato nella tabella 1.

Tabella 1. Modalità di associazione supportate

Modalità di binding Descrizione
TwoWay Sposta le modifiche, dal controllo associato o dall'origine dell'associazione, a un'altra in modo bidirezionale. Questa è la modalità predefinita.
Oneway Sposta le modifiche solo dall'origine al controllo. Quando si verificano modifiche nell'origine, i dati del controllo associato vengono modificati.
Onetime I dati vengono associati solo all'avvio e le modifiche apportate all'origine vengono ignorate una volta che il controllo viene riempito con i dati la prima volta.

È possibile specificare la modalità semplicemente includendo la modalità nel markup, come indicato di seguito.

{Binding ElementName=theTextBox, Path=Text, Mode=OneTime}

Un modo per vedere come funziona l'associazione bidirezionale consiste nel creare un canvas con due caselle di testo, una associata all'altra.

<Window    
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  >
  <Canvas>
    <TextBox Name="theTextBox" Text="Hello" />
    <TextBox Canvas.Top="25"
             Text="{Binding ElementName=theTextBox, Path=Text, Mode=TwoWay}" />
  </Canvas>
</Window>

Se si incolla questo codice nello strumento XAMLPad fornito con l'SDK, si noti che la casella di testo di origine aggiorna la casella di testo associata come si digita, ma l'aggiornamento dal controllo associato al controllo del codice sorgente si verifica solo quando il controllo associato perde lo stato attivo. Se si modifica la modalità in OneWay o OneTime, è possibile vedere come queste diverse modalità cambiano il modo in cui funzionano le associazioni.

Controllo del tempo di associazione

Oltre alla modalità, è anche possibile specificare quando l'associazione esegue il push delle modifiche usando UpdateSourceTrigger. È possibile specificare che l'associazione apporta la modifica solo in un momento specificato, specificando il tipo UpdateSourceTrigger .

{Binding ElementName=theTextBox, Path=Text, UpdateSourceTrigger=LostFocus}

La proprietà UpdateSourceTrigger specifica quando aggiornare l'origine con modifiche. Questo valore è valido solo con le associazioni Mode=TwoWay (ovvero l'impostazione predefinita). I valori validi per UpdateSourceTrigger vengono visualizzati nella tabella 2.

Tabella 2. Valori UpdateSourceTrigger

UpdateSourceTrigger Descrizione
Esplicita L'origine viene aggiornata solo chiamando in modo esplicito il metodo BindingExpression.UpdateSource .
LostFocus L'origine viene aggiornata quando il controllo associato perde lo stato attivo.
PropertyChanged Le modifiche vengono aggiornate all'origine ogni volta che la proprietà cambia. Questo è il comportamento predefinito.

Uso di DataContext

L'ultimo concetto da coprire in questo articolo è come usare DataContext. DataContext viene usato specificamente per specificare che tutti i controlli all'interno di alcuni contenitori verranno associati a un oggetto comune.

Ad esempio, di seguito è riportato un esempio in cui è presente un canvas che mostrerà il valore e il testo di un nodo specifico nel documento XML.

<StackPanel 
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  >
  <StackPanel.Resources>
    <XmlDataProvider x:Key="FavoriteColors">
      <Colors >
        <Color ID="1">Blue</Color> 
        <Color ID="2">Black</Color> 
        <Color ID="3">Green</Color> 
        <Color ID="4">Red</Color> 
      </Colors>
    </XmlDataProvider>
  </StackPanel.Resources>
  <TextBlock HorizontalAlignment="Center" 
             FontWeight="Bold">
    XML DataContext Example
  </TextBlock>
  <Canvas DataContext="{Binding Source={StaticResource FavoriteColors},                         XPath='/Colors/Color[@ID=2]'}">
    <TextBlock Text="{Binding XPath=@ID}" />
    <TextBlock Canvas.Top="25" Text="{Binding XPath=.}" />
  </Canvas>
</StackPanel>

Impostando DataContext sul documento XML (e un'espressione XPath specifica), viene detto che tutti i controlli all'interno di che non contengono un'origine possono usare DataContext del contenitore. In questo modo, è possibile associare textBlocks specificando semplicemente espressioni XPath . Si noti che le espressioni XPath in ognuna delle espressioni TextBlocksono espressioni XPath relative. Si tratta dello stesso per l'associazione a oggetti.

<Window 
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    Title="Simple Source Binding"
    x:Class="XamlExamples.SimpleSource"
  >
  <Window.Resources>
    <ObjectDataProvider TypeName="XamlExamples.MyStrings, XamlExamples"
                        x:Key="MyStringData" />
  </Window.Resources>  
    <StackPanel>
      <TextBlock HorizontalAlignment="Center" 
               FontWeight="Bold">
      Object DataContext Example
    </TextBlock>
    <Canvas DataContext="{Binding Source={StaticResource MyStringData}}">
      <TextBlock Text="{Binding Path=Length}" />
      <TextBlock Canvas.Top="25" Text="{Binding Path=Item[0]}" />
    </Canvas>
  </StackPanel>
</Window>

L'uso di oggetti anziché XML significa semplicemente che si vogliono usare espressioni Path anziché espressioni XPath .

Dove siamo?

È stato illustrato come eseguire il data binding direttamente in XAML con l'oggetto Binding , sia in versioni shorthand che longhand. Usando i provider di dati XML o Object, è possibile associare diversi tipi di oggetti nelle applicazioni. È stato anche illustrato come eseguire l'associazione ad altri controlli usando la sintassi ElementName dell'oggetto Binding . Nella prossima parte di questa serie verranno illustrate le informazioni e l'associazione ai dati reali del database, usando oggetti personalizzati o contenitori di dati .NET, ad esempio DataSources e DataSet.

Riferimenti