Basic Examples of WPF Data Binding

Scope

This article intends to introduce the concept of Data Binding in WPF, presenting, as an example, a DataGrid that is populated using a custom List(Of). Data will be edited using controls suach as TextBox and DatePicker that will take their data source from the grid itself.

Introduction

It is widely known that one of the major features introduced with Windows Presentation Foundation resides in the ability to easily connect the user controls (and objects) with data sources of various complexities, leaving the task of their representation to the framework (on which you can always apply later customizations, nonetheless). As an example of a possible usage scenario, we assume here to have a grid expose data from a given customized structure and later to make possible its variation using simple text controls.

An example class

Let's suppose we have a hypothetical class Articolo, that will allow us to define products to store, in their terms of product's code (Codice), a description (Descrizione), and expiration date (DataScadenza). We'll declare that the class is reductive, but useful for our means, as follows.
  1. Public Class Articolo  
  2.         Dim _codice As String  
  3.         Dim _descrizione As String  
  4.         Dim _datascadenza As Date  
  5.    
  6.         Public ReadOnly Property Codice As String  
  7.             Get  
  8.                 Return _codice  
  9.             End Get  
  10.         End Property  
  11.    
  12.         Public Property Descrizione As String  
  13.             Get  
  14.                 Return _descrizione  
  15.             End Get  
  16.             Set(value As String)  
  17.                 _descrizione = value  
  18.             End Set  
  19.         End Property  
  20.    
  21.         Public Property DataScadenza As Date  
  22.             Get  
  23.                 Return _datascadenza  
  24.             End Get  
  25.             Set(value As Date)  
  26.                 _datascadenza = value  
  27.             End Set  
  28.         End Property  
  29.    
  30.         Public Sub New(codart As String, desart As String)  
  31.             _codice = codart  
  32.             _descrizione = desart  
  33.             _datascadenza = New Date(Now.Year + 1, Now.Month, Now.Day)  
  34.         End Sub  
  35. End Class  
In the class constructor only the parameters for code and description are requested. The expiration date is set a year in the future. Properties that define the class are editable, with the only exception of Codice (product code), that cannot be altered after its creation.
 
Next, we'll populate a list of products with some example data, useful for the next steps. Let's suppose we have a WPF window named MainWindow.xaml. We'll create an event manager for the Loaded event, such as the XAML resembling the following.
  1. <Window  
  2.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
  3.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
  4.     xmlns:local="clr-namespace:ERP_test" x:Class="MainWindow"  
  5.     Title="MainWindow" Height="269" Width="563" Loaded="Window_Loaded">  
  6. </Window>  

The code behind the event will be:

  1. Dim prodotti As List(Of Articolo)  
  2. Private Sub Window_Loaded(sender As Object, e As RoutedEventArgs)  
  3.     prodotti = New List(Of Articolo)  
  4.     prodotti.Add(New Articolo("Prodotto01""ARTICOLO TEST"))  
  5.     prodotti.Add(New Articolo("Prodotto02""PROVA"))  
  6.     prodotti.Add(New Articolo("Prodotto03""NESSUNA DESCRIZIONE"))  
  7. End Sub  
Simply enough, we'll have now a List(Of Articolo) global to the window and named prodotti that contains three products at first execution. That structure represents the data source we'll expose, using binding, in a DataGrid. Let's see how.

Data Binding on DataGrid

In our window we'll add a DataGrid control, named DataGrid1. Having our structure defined code-side, we must work on this side to link the control to its data source. The binding will be obtained using the control's ItemsSource property. Our Loaded event will be modified as follows.
  1. Dim prodotti As List(Of Articolo)  
  2.   
  3. Private Sub Window_Loaded(sender As Object, e As RoutedEventArgs)  
  4.     prodotti = New List(Of Articolo)  
  5.   
  6.     prodotti.Add(New Articolo("Prodotto01""ARTICOLO TEST"))  
  7.     prodotti.Add(New Articolo("Prodotto02""PROVA"))  
  8.     prodotti.Add(New Articolo("Prodotto03""NESSUNA DESCRIZIONE"))  
  9.   
  10.     DataGrid1.ItemsSource = prodotti  
  11. End Sub  
ItemsSource is indeed the property (of the System.Collections.IEnumerable type) using which we'll set (or read) a data collection, the latter used for the control's content generation (in our case, the grid). The binding on the DataGrid is up: from a first execution of our program, we'll see an output like this.
 
1663.0842.datab01.png_2D00_550x0.png (550×406)

Data Binding between controls: Datagrid on TextBox and DatePicker

As previously described, we are not interested in having a mere list of products. We want to be able to view the product's details scrolling that list. In realizing this kind of implementation, we'll use some TextBoxes, executing a binding between them (as recipients) and the DataGrid (the source), allowing recipient controls (TextBox, or DatePicker in case of expiration date) to modify their source in turn. Let's modify our window as follows.
 
3568.5141.datab02.png_2D00_550x0.png (550×491) 
 
The properties that expose the control's value in the TextBox and DatePicker are, respectively, Text and SelectedDate. It is therefore necessary to set the data binding on these properties. Essentially, after individuating the property that will receive a specific data, we must indicate its source, and other information (some of which are optional) that will determine how the data are exchanged. In our case, desiring to modify the content of DataGrid using the variation of recipient controls, we must use some kind of bidirectional approach.
 
As operations to be executed between controls, it is possible to intervene directly on XAML code, indicating how TextBoxes and the DatePicker must be linked to the DataGrid. The code pertinent to the three controls will be modified as follows.
  1. <TextBox HorizontalAlignment="Left" Height="23" Margin="445,42,0,0"  
  2.          TextWrapping="Wrap" VerticalAlignment="Top" Width="181"  
  3.          Text="{Binding SelectedItem.Codice,ElementName=DataGrid1 , Mode=OneWay }"/>  
  4.    
  5. <TextBox HorizontalAlignment="Left" Height="23" Margin="445,70,0,0"  
  6.          TextWrapping="Wrap" VerticalAlignment="Top" Width="181"  
  7.          Text="{Binding SelectedItem.Descrizione,ElementName=DataGrid1 , Mode=TwoWay }"/>  
  8.    
  9. <DatePicker HorizontalAlignment="Left" Margin="445,98,0,0"  
  10.             VerticalAlignment="Top" Width="181"  
  11.             SelectedDate="{Binding SelectedItem.DataScadenza,ElementName=DataGrid1 ,Mode=TwoWay }"/>  
As mentioned, properties that expose a certain data must be set indicating the source of the data, and the mode in which the data must be retrieved. We take case #1 (TextBox that exposes a product's code, Codice) as an example.
 
2728.bind.png (550×200) 
 
In this case, we'll see the source control is set on DataGrid1, from which we read the Codice property (belonging to the Articolo class) of the currently SelectedItem. The Binding's mode is mono-directional, that is from the source (DataGrid1) to the destination (TextBox), and not vice versa. In fact, we defined the Codice property as read-only (see snippet 1) and any attempt to change its value will raise an exception.
 
Similarly, in the two remaining cases we'll have always DataGrid1 as source control, referenced properties will be Descrizione (description) and DataScadenza (expiration date), but the binding’s mode will be TwoWay, or bidirectional: modifying the control’s content will result in updating its source property/control, or DataGrid1 (and, for extension, the list connected to it).
 
Running our program, and trying to position ourselves on the second record (for example) and modifying the data, we can verify the proper update of linked control’s data:
 
1464.2678.datab04.png_2D00_550x0.png (550×209) 

Afterwords: Alternative method for DataGrid population

We saw here a method for populating a DataGrid that involves a List(Of <Our_Class>). Speaking of WPF binding flexibility, there are other methods using which we could populate the contents of a control. For example, our class Articolo could be referred directly into the XAML of our grid. If we desire to provide our DataGrid some records to start with, we could do that as follows.
  1. <DataGrid Name="DG1" HorizontalAlignment="Left" Height="153" Margin="10,10,0,0" VerticalAlignment="Top" Width="305" xmlns:local="clr-namespace:WinTest"  >  
  2.             <DataGrid.Columns >  
  3.                 <DataGridTextColumn Header="Codice" Binding="{Binding Codice}"/>  
  4.                 <DataGridTextColumn Header="Descrizione" Binding="{Binding Descrizione}"/>  
  5.                 <DataGridTextColumn Header="Data di scadenza" Binding="{Binding DataScadenza}"/>  
  6.             </DataGrid.Columns>  
  7.             <local:Articolo Codice="CODE_01" Descrizione="MSDN TEST" DataScadenza="2014-12-01" />  
  8. </DataGrid>  
We use the xmlns:local keyword to specify our class as a reference (in my case, WinTest). This way, we could use in the XAML each class defined within our namespace (in my case, Articolo). We then define three DataGridColumns, each one bound with a specific property of our class. Then, with the tag local, we could proceed in defining a variable number of records, setting each of its parameters. The code above will produce the following window.
 
8156.Senza-nome.png (333×213)
 
From a situation like that, we could add other rows code-side, using the Item collection exposed by DataGrid. Assuming our DataGrid's name is DataGrid1, we could, for example, add a second row to it, using in the Loaded event something like that.
  1. DataGrid1.Items.Add( New Articolo("CODE_02""MSDN TEST 2") )  
 Running now our program will result in the following window.
 
0246.Senza-nome1.png (333×213) 
 
Please note: as far as there are dynamically or statically generated rows, in other words the Item collection is not empty, it's not possibile to use the ItemsSource property discussed above. In order to bind a structure to our DataGrid, we must first empty Item collection (for example, with something like: DataGrid1.Items.Clear()), and only then we'll be able to successfully set the ItemsSource property.

Conclusion 

Obviously, we had discussed here a small example, compared to the potential offered by such technology: nonetheless, I hope it was useful for those approaching this method for the first time. Happy coding.