Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

DataBinding Expression in WPF

0.00/5 (No votes)
20 Jan 2017 1  
In this article let’s explore the different types of DataBinding Expressions provided by WPF.

There are lot of articles discussing about the concept of Binding and explaining how to bind properties using StaticResources and DynamicResources. These concepts use the DataBinding expressions provided by WPF. In this article let’s explore the different types of DataBinding Expressions provided by WPF.

Introduction

DataBinding is a powerful technique that allows the flow of data between UI Elements and Business model. It reflects the changes automatically to UI element as soon as the data in Business model changes.

Modes of DataBinding

Modes Description
OneWay Source → Destination
TwoWay Source ←→ Destination
OneWayToSource Source ← Destination
OneTime Source → Destination (only once)

This can be achieved by different types of DataBinding Expression provided by WPF.

Types of DataBinding Expressions

  • DataContext Binding
  • RelativeSource Binding
  • Current Item of Collection Binding

DataContext Binding

DataContext is a Dependency property which is a default source of binding. Datacontext is inherited along the logical tree. So, if you set a datacontext to a control all the child elements in logical tree will also refer to the same datacontext, unless and until another source is specified explicitly.

Let’s take an example to understand it in more detail

  1. Create a class Book as shown below
public class Book
    {
        public string Name { get; set; }
        public string Author { get; set; }
    }
  1. Add a XAML file DataContextBinding.xaml and place four Textblocks as shown below:
<Grid VerticalAlignment="Center">
    <Grid.RowDefinitions>
        <RowDefinition Height="40"/>
        <RowDefinition Height="40"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="Auto"/>
    </Grid.ColumnDefinitions>
    <TextBlock Text="Book Name:" FontWeight="Bold"/>
    <TextBlock Grid.Column="1" />
    <TextBlock Text="Author:" FontWeight="Bold" Grid.Row="1"/>			   	  
    <TextBlock Grid.Row="1" Grid.Column="1"/>
</Grid>
  1. Now Let’s see how this DataContext Property is used to display data

    It is used in two ways:

    1. Using {Binding} expression - Used to bind the DataContext directly.

      Create an instance of class Book, initialize its properties and assign Name property of class to the DataContext property of Window.

      public partial class DataContextBinding : Window
          {
                  public DataContextBinding()
                  {
                          InitializeComponent();
                          //Create the instance
                          Book book = new Book();
                          //initialize the properties
                          book.Name = "Computer Networking";
                          //Assign the Property as DataContext
                          this.DataContext = book.Name;
              }
       }
      

      As the Datacontext is inherited along the logical tree and the data book. Name is bound to Control Window, All the child elements of Window will also refer to same object (book.Name)

      To Display the data, bind the DataContext with the Textblock as below

      <TextBlock Text="Book Name:" FontWeight="Bold"/>
      <TextBlock Text="{Binding}" Grid.Column="1" />

      OUTPUT

    2. Using {Binding Property} expression - Binds the Property of Datacontext.

      Create an instance of class Book, initialize its properties and assign instance of class (book) to the DataContext property of Window.

      Book book = new Book();
      //initialize the properties
      book.Name = "Computer Networking";
      book.Author = "James F. Kurose";
      //Assign the instance as DataContext
      this.DataContext = book;

      Now let’s see the output.

      As the Binding expression {Binding} is used to bind the DataContext object of type Book, ToString() method is called on it and the data is shown as string.

      To Display data in proper format we have to bind the properties of data object with the Textblocks as below:

      <TextBlock Text="Book Name:" FontWeight="Bold"/>
      <TextBlock Text="{Binding Name}" Grid.Column="1" />
      <TextBlock Text="Author:" FontWeight="Bold" Grid.Row="1" />
      <TextBlock Text="{Binding Author}" Grid.Row="1" Grid.Column="1"/>

      Binding expression {Binding Name} is used to bind the Name property of DataContext bound.

      OUTPUT

RelativeSource Binding

RelativeSource is property which sets the binding source with the relative relation to binding target. This extension is majorly used when you have to bind one property of the element to another property of same element.

There are four types of RelativeSource:

  1. Self
  2. FindAncestor
  3. TemplatedParent
  4. PreviousData

Let’s explore them one-by-one in detail.

Self

Self is used in a scenario when the Binding source and the binding target are same. One property of the object is bind with another property of same object.

For example: Let’s take an Ellipse with same height and width

Add the below code in the XAML file. Width property is bind with height property relatively.

<Grid>
        <Ellipse Fill="Black" Height="100" 
          Width="{Binding RelativeSource={RelativeSource Self},Path=Height}">
        </Ellipse>
</Grid>

OUTPUT

If the Height of Ellipse is changed the Width will also change relatively.

FindAncestor

As the name says, this is used when binding source is one of the Ancestors (Parents) of the binding target. Using FindAncestor extension you can find ancestor up to any level.

Let’s take an example to understand it more clearly.

Steps

Create a XAML representing the below logical tree of elements

<Grid Name="Parent_3">
        <StackPanel Name="Parent_2">
            <Border Name="Parent_1">
                <StackPanel x:Name="Parent_0" Orientation="Vertical" >
                    <Button></Button>                  
                </StackPanel>
            </Border>           
        </StackPanel>       
    </Grid>

Now let’s use FindAncestor extension to bind the Name Property of ancestors to the Content Property of Child element Button.

<Grid Name="Parent_3">
        <StackPanel Name="Parent_2" HorizontalAlignment="Center" VerticalAlignment="Center" Width="100">
            <Border Name="Parent_1">
                <StackPanel  x:Name="Parent_0" Orientation="Vertical" >
                    <Button Height="50" 
                        Content="{Binding RelativeSource={RelativeSource FindAncestor,
                           AncestorType={x:Type StackPanel}, 
                           AncestorLevel=2},Path=Name}"></Button>                  
                </StackPanel>
            </Border>           
        </StackPanel>       
    </Grid>

OUPUT

AncestorType "StackPanel" in combination with AcestorLevel as "2" binds the Content property of button with Name Property of StackPanel (Parent_2).

TemplatedParent

TemplatedParent is Property which enables you to create a Control template with few unknown values. These values depend on properties of control that ControlTemplate is applied to.

Let’s take an example to understand it in more detail

Steps

  1. Create a ControlTemplate for button as shown below
         <Window.Resources>
                <ControlTemplate x:Key="template">
                    <Canvas>
                    <Ellipse Height="110" Width="155" 
                         Fill="Black"/>
                        <Ellipse Height="100" Width="150" 
                         Fill="{Binding RelativeSource={RelativeSource TemplatedParent},
                    		Path=Background}">
                    </Ellipse>
                    <ContentPresenter Margin="35" 
    Content="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Content}"/>
                    </Canvas>
                </ControlTemplate>
            </Window.Resources>

    In the above code sample Fill Property of Ellipse and Content Property of ContentPresenter is dependent on the values of properties of control to which this template will be applied.

  2. Add a button and apply the template to it
    <Button Margin="50" Background="Beige"
          Template="{StaticResource template}" Height="0"
          Content="Click me" FontSize="22">
    </Button>

    As the template is applied, the Background (Beige) of Button is relatively bind with Fill Property of Ellipse and Content (Click me) is relatively bind with Content property of ContentPresenter. The dependent values are evaluated and gives the below output.

    OUTPUT

PreviousData

This is the least used mode of RelativeSource. This comes into picture when a data is analyzed and we need to represent the change in values with respect to previous data.

Let’s take an example to understand it in more detail

Steps

  1. Create a class Data and implement INotifyPropertyChanged interface as shown below
    public class Data : INotifyPropertyChanged
        {
            public int DataValue { get; set; }
            public event PropertyChangedEventHandler PropertyChanged;
    
            protected void OnPropertyChanged(string PropertyName)
            {
                if (null != PropertyChanged)
                {
                    PropertyChanged(this,
                         new PropertyChangedEventArgs(PropertyName));
                }
            }
        }
  2. Create a list to type Data and assign it as the DataContext
    public RelativeSourcePreviousData()
            {
                InitializeComponent();
                List<Data> data = new List<Data>();
                data.Add(new Data() { DataValue = 60 });
                data.Add(new Data() { DataValue = 100 });
                data.Add(new Data() { DataValue = 120 });
                this.DataContext = data;
               
            }
  3. Add ItemsControl in XAML file
    <ItemsControl ItemsSource="{Binding}"></ItemsControl>
  4. Create ItemsPanel Template for it as below
    <ItemsControl ItemsSource="{Binding}">
                 		 <ItemsControl.ItemsPanel>
                    			<ItemsPanelTemplate>
                        			<StackPanel Orientation="Vertical" />
                    			</ItemsPanelTemplate>
              		  </ItemsControl.ItemsPanel>
    </ItemsControl>
  5. Now for proper representation of data create DataTemplate as below
    <ItemsControl.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <Grid Margin="30,20,0,0">
    <Rectangle Width="80" Height="{Binding DataValue}"               Fill="Blue"/>
    <TextBlock Foreground="White" Margin="35,0,0,0" Text="{Binding DataValue}"></TextBlock>
                     </Grid>
                     <TextBlock Margin="30,20,0,0" Text="Previous Data:"></TextBlock>
                     <TextBlock VerticalAlignment="Center" Margin="5,20,0,0" Text="{Binding 
                       RelativeSource={RelativeSource PreviousData}, Path=DataValue}"/>
                </StackPanel>                    
            </DataTemplate>
       </ItemsControl.ItemTemplate>

    OUTPUT

The Height of Blue boxes is the value of the items in List and the Previous Data is shown at right with respect to boxes. The first value of the item is "60". Therefore the Previous data shows no value for first item.

Current Item of Collection Binding

This is used when you are working with Collection. You can read the properties of SelectedItem very easily using this binding expression. The slash is special operator which used to deal with current item in the collection.

There three kind of expressions used

  1. {Binding / }
  2. {Binding Collection / }
  3. {Binding Collection / Property}

{Binding / }

This expression is used to bind the current item in the DataContext.

Let’s take an example:

In below example DataContext is Collection of Countries of string type and same is bind with the Listbox

Steps

  1. Create a class Countries and add a method GetCountriesName() that returns the collection of Countries of string data type as below:
    public class Countries
        {
          public static List<string> GetCountriesName()
          {
              List<string> countries = new List<string>();
              foreach (CultureInfo culture in CultureInfo.GetCultures(CultureTypes.SpecificCultures))
              {
                  RegionInfo country = new RegionInfo(culture.LCID);
                  if (!countries.Contains(country.EnglishName))
                      countries.Add(country.EnglishName);
              }
              countries.Sort();
              return countries;
          }
      }
    
  2. Add a XAML file add Listbox and TextBlock as shown below
    <DockPanel Name="Collection">
                <ListBox ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True">
                </ListBox>
                <TextBlock DockPanel.Dock="Top"/>
    </DockPanel>
  3. Create the instance of class Countries and assign the Collection of Countries as the DataContext
    public CurrentItemCollection()
            {
                InitializeComponent();
                Countries countries = new Countries();
                this.DataContext = countries.GetCountriesName()
    
            }
  4. Bind the Text property of TextBlock to bind it with current selected item of collection as below
    <TextBlock DockPanel.Dock="Top" Text="{Binding /}" />

    OUTPUT

    As soon as the item is selected Item, it displays the selected country on right.

{Binding Collection / }

This expression is used to bind the current item of the Collection Property within the DataContext.

Example

DataContext is Countries class

Collection Property is CounriesList which is bind with the ListBox

Steps

  1. Use the same class Countries created above with a slight difference. Create a method with return type RegionInfo
    public static List<RegionInfo> GetCountries()
            {
                List<RegionInfo> countries = new List<RegionInfo>();
                foreach (CultureInfo culture in CultureInfo.GetCultures(CultureTypes.SpecificCultures))
                {
                    RegionInfo country = new RegionInfo(culture.LCID);
                    if (countries.Where(p => p.Name == country.Name).Count() == 0)
                        countries.Add(country);
                }
                return countries.OrderBy(p => p.EnglishName).ToList();
            }
  2. Add a CountriesList Property of type RegionInfo
    private List<RegionInfo> countries = null;
     public List<RegionInfo> CountriesList
     {
         get
         {
             if (countries == null)
                 countries = GetCountries();
             return countries;
         }
     }
    

    Below is screenshots of values in CountriesList collection

  3. Specify the class Countries as the DataContext and bind the Listbox with the CountriesList Property of DataContext
    <Window.Resources>
            <vm:Countries x:Key="Countries"></vm:Countries>
        </Window.Resources>
        <Grid>
            <DockPanel Name="Collection" DataContext="{StaticResource Countries}">
                <ListBox ItemsSource="{Binding CountriesList}"
               IsSynchronizedWithCurrentItem="True">
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding EnglishName}"></TextBlock>
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>
                
            </DockPanel>
            
        </Grid>
  4. To evaluate the current item of CountriesList property binds the Text property of TextBlock as below.
    <TextBlock DockPanel.Dock="Top"
    Text="{Binding CountriesList/}" HorizontalAlignment="Center" FontSize="16" VerticalAlignment="Center"
    />

    OUTPUT

    Right side displays the current item of the Collection (CountriesList) within the DataContext (Countries)

{Binding Collection / Property}

This expression is used to bind the Property of current item of Collection within the DataContext

For example, if we have to evaluate a specific property of current item of CountriesList collection.

In this example I want to show value of property "EnglishName ".

To do so, bind the Text Property of TextBlock as below

<TextBlock DockPanel.Dock="Top"
Text="{Binding CountriesList/EnglishName}" />

Output

Now it shows the value of Property "EnglishName" as the item in the list is selected.

Conclusion

I have covered all the data binding expressions is detail. I hope this helps you to understand the concept of Binding and expressions provided by WPF.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here