Category Archives: Binding Object Properties – Path

Binding Object Properties – Path

 

Path:

Binding Path property is the path to the element property being used as the data source. Path is used to indicate from which property on the source object to get and set the bound data value. It is a property of type PropertyPath, which allows it to support a complex range of path expressions.

In the source code, we have a TextBox which is bound to the Name property of a Employee object. Here’s an abridged version of the XAML I’m referring to:

Code Snippet
<TextBox Grid.Row="2" Text="{Binding EmployeeName}"></TextBox>

Notice that the binding statement in the XAML snippet above does not explicitly mention that it is setting the Binding‘s Path property. Markup extensions, such as Binding, can have one property which acts as the "default" property when being set in XAML. Binding‘s default property is Path. If you are not in favor of using implicit notation like that, the XAML seen below is equivalent to the previous snippet:

Code Snippet
<TextBox Grid.Row="2" Text="{Binding Path=EmployeeName}"></TextBox>

Using Path=.

Observe the line 7 in the following code. In the employee class, I have two properties EmployeeName and State. So in the Grid DataContext, I am setting binding as Path=., which means the grid and all the controls in  it can get access to all the properties in the DataContext. Line 19 and line20 uses the EmployeeName and line21 uses the state property.

Code Snippet
  1. <Window x:Class="Bindingtoclasses.MainWindow"
  2.         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
  3.         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;
  4.         xmlns:src="clr-namespace:Bindingtoclasses"
  5.  
  6.         Title="MainWindow" Height="350" Width="525">
  7.     <Grid DataContext="{Binding Path=.}">
  8.         <Grid.Resources>
  9.                 <src:Employee x:Key="myDataSource" EmployeeName="Kishore1021"/>
  10.         </Grid.Resources>
  11.         <Grid.RowDefinitions>
  12.             <RowDefinition Height="*"></RowDefinition>
  13.             <RowDefinition Height="*"></RowDefinition>
  14.             <RowDefinition Height="*"></RowDefinition>
  15.             <RowDefinition Height="*"></RowDefinition>
  16.         </Grid.RowDefinitions>
  17.         <TextBox Grid.Row="0" Text="{Binding Source={StaticResource myDataSource}, Path=EmployeeName, UpdateSourceTrigger=PropertyChanged}"/>
  18.         <TextBox Grid.Row="1" Text="{Binding Source= {StaticResource myDataSource}, Path=EmployeeName}"></TextBox>
  19.         <TextBox Grid.Row="3" Text="{Binding Path=EmployeeName, Mode=TwoWay}"></TextBox>
  20.         <TextBox Grid.Row="2" Text="{Binding Path=EmployeeName, Mode=OneWayToSource}"></TextBox>
  21.         <TextBlock Text="{Binding Path=State}"/>
  22.         
  23.     </Grid>
  24. </Window>

 

The Output of the program is as follows

image

Consider the following class where I have a class Employee that contains two properties EmployeeName and State. I have one more class called AnotherClass and have AnotherField as a property along with the EmployeeNameTest property which corresponds to the Employee class object. From line 23 to 28, we are creating an Employee object and initializing it with some values. And then created the AnotherClass object and used the previously created Employee object and assigned it to the property EmployeeNameTest. Finally, we are assigning the AnotherClass object c to this windows DataContext in line 28 in the following code.

Code Snippet
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Windows;
  6. using System.Windows.Controls;
  7. using System.Windows.Data;
  8. using System.Windows.Documents;
  9. using System.Windows.Input;
  10. using System.Windows.Media;
  11. using System.Windows.Media.Imaging;
  12. using System.Windows.Navigation;
  13. using System.Windows.Shapes;
  14. using System.ComponentModel;
  15.  
  16. namespace Bindingtoclasses
  17. {
  18.     public partial class MainWindow : Window
  19.     {
  20.         public MainWindow()
  21.         {
  22.             InitializeComponent();
  23.             Employee P = new Employee("Hello World");
  24.             P.State = "MD";
  25.             AnotherClass c = new AnotherClass();
  26.             c.EmployeeNameTest = P;
  27.             c.AnotherField = "Another Value";
  28.             this.DataContext = c;
  29.         }
  30.     }
  31.  
  32.     public class AnotherClass : INotifyPropertyChanged
  33.     {
  34.  
  35.         private string anotherfield;
  36.         private Employee emp;
  37.  
  38.  
  39.         public string AnotherField
  40.         {
  41.             get { return anotherfield; }
  42.             set
  43.             {
  44.                 anotherfield = value;
  45.                 OnPropertyChanged("AnotherField");
  46.             }
  47.         }
  48.  
  49.         public Employee EmployeeNameTest
  50.         {
  51.             get { return emp; }
  52.             set
  53.             {
  54.                 emp = value;
  55.                 OnPropertyChanged("EmployeeNameTest");
  56.             }
  57.         }
  58.  
  59.         public event PropertyChangedEventHandler PropertyChanged;
  60.  
  61.         //// Create the OnPropertyChanged method to raise the event
  62.         protected void OnPropertyChanged(string name)
  63.         {
  64.             PropertyChangedEventHandler handler = PropertyChanged;
  65.             if (handler != null)
  66.             {
  67.                 handler(this, new PropertyChangedEventArgs(name));
  68.             }
  69.         }
  70.  
  71.     }
  72.  
  73.     // This class implements INotifyPropertyChanged to support one-way and two-way bindings
  74.     // (such that the UI element updates when the source has been changed dynamically)
  75.     public class Employee : INotifyPropertyChanged
  76.     {
  77.         private string name;
  78.         private string state;
  79.         // Declare the event
  80.         public event PropertyChangedEventHandler PropertyChanged;
  81.  
  82.         public Employee()
  83.         {
  84.         }
  85.  
  86.         public Employee(string value)
  87.         {
  88.             this.name = value;
  89.         }
  90.  
  91.         public string EmployeeName
  92.         {
  93.             get { return name; }
  94.             set
  95.             {
  96.                 name = value;
  97.                 // Call OnPropertyChanged whenever the property is updated
  98.                OnPropertyChanged("EmployeeName");
  99.             }
  100.         }
  101.  
  102.         public string State
  103.         {
  104.             get { return state; }
  105.             set
  106.             {
  107.                 state = value;
  108.                 OnPropertyChanged("State");
  109.             }
  110.         }
  111.  
  112.         //// Create the OnPropertyChanged method to raise the event
  113.         protected void OnPropertyChanged(string name)
  114.         {
  115.             PropertyChangedEventHandler handler = PropertyChanged;
  116.             if (handler != null)
  117.             {
  118.                 handler(this, new PropertyChangedEventArgs(name));
  119.             }
  120.         }
  121.     }
  122.  
  123. }

 

The XAML for the above class to display the values is as follows. Points to notice from the XAML are

  • In Line 7, we are using a period (.) path to bind to the current source which we set in the above code Line28 (this.DataContext = c).
  • In Line 24, (Path=AnotherField); AnotherField is the name of the property of the source object to use for the binding. So the 5th textblock shows the AnotherField value when it binds.
  • Line 21 & 22, (EmployeeNameTest.EmployeeName). This is concept of Subproperties. Subproperties of a property can be specified by a syntax in C# using ObjectName.PropertyName. For instance, the clause Path=EmployeeNameTest.EmployeeName sets the binding to the subproperty EmployeeName of the object or property EmployeeNameTest.
Code Snippet
  1. <Window x:Class="Bindingtoclasses.MainWindow"
  2.         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
  3.         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;
  4.         xmlns:src="clr-namespace:Bindingtoclasses"
  5.  
  6.         Title="MainWindow" Height="350" Width="525">
  7.     <Grid DataContext="{Binding Path=.}">
  8.         <Grid.Resources>
  9.                 <src:Employee x:Key="myDataSource" EmployeeName="Kishore1021"/>
  10.         </Grid.Resources>
  11.         <Grid.RowDefinitions>
  12.             <RowDefinition Height="*"></RowDefinition>
  13.             <RowDefinition Height="*"></RowDefinition>
  14.             <RowDefinition Height="*"></RowDefinition>
  15.             <RowDefinition Height="*"></RowDefinition>
  16.             <RowDefinition Height="*"></RowDefinition>
  17.             <RowDefinition Height="*"></RowDefinition>
  18.         </Grid.RowDefinitions>
  19.         <TextBox Grid.Row="0" Text="{Binding Source={StaticResource myDataSource}, Path=EmployeeName, UpdateSourceTrigger=PropertyChanged}"/>
  20.         <TextBox Grid.Row="1" Text="{Binding Source= {StaticResource myDataSource}, Path=EmployeeName}"></TextBox>
  21.         <TextBox Grid.Row="2" Text="{Binding Path=EmployeeNameTest.EmployeeName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></TextBox>
  22.         <TextBox Grid.Row="3" Text="{Binding Path=EmployeeNameTest.EmployeeName}"></TextBox>
  23.         <TextBlock Grid.Row="4" Text="{Binding Path=EmployeeNameTest.EmployeeName}"/>
  24.         <TextBlock Grid.Row="5" Text="{Binding Path=AnotherField}"/>
  25.         
  26.     </Grid>
  27. </Window>

You can download the source code form here.

Observe the class Employee shown below. We have a property EmployeeName.

Code Snippet
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Windows;
  6. using System.Windows.Controls;
  7. using System.Windows.Data;
  8. using System.Windows.Documents;
  9. using System.Windows.Input;
  10. using System.Windows.Media;
  11. using System.Windows.Media.Imaging;
  12. using System.Windows.Navigation;
  13. using System.Windows.Shapes;
  14. using System.ComponentModel;
  15.  
  16. namespace Bindingtoclasses
  17. {
  18.     public partial class MainWindow : Window
  19.     {
  20.         public MainWindow()
  21.         {
  22.             InitializeComponent();
  23.             Employee P = new Employee("Hello World");
  24.             this.DataContext = P;
  25.         }
  26.     }
  27.  
  28.     // This class implements INotifyPropertyChanged to support one-way and two-way bindings
  29.     // (such that the UI element updates when the source has been changed dynamically)
  30.     public class Employee : INotifyPropertyChanged
  31.     {
  32.         private string name;
  33.         // Declare the event
  34.         public event PropertyChangedEventHandler PropertyChanged;
  35.  
  36.         public Employee()
  37.         {
  38.         }
  39.  
  40.         public Employee(string value)
  41.         {
  42.             this.name = value;
  43.         }
  44.  
  45.         public string EmployeeName
  46.         {
  47.             get { return name; }
  48.             set
  49.             {
  50.                 name = value;
  51.                 // Call OnPropertyChanged whenever the property is updated
  52.                OnPropertyChanged("EmployeeName");
  53.             }
  54.         }
  55.  
  56.         //// Create the OnPropertyChanged method to raise the event
  57.         protected void OnPropertyChanged(string name)
  58.         {
  59.             PropertyChangedEventHandler handler = PropertyChanged;
  60.             if (handler != null)
  61.             {
  62.                 handler(this, new PropertyChangedEventArgs(name));
  63.             }
  64.         }
  65.     }
  66.  
  67. }

XAML to display the EmployeeName is shown below.

Code Snippet
  1. <Window x:Class="Bindingtoclasses.MainWindow"
  2.         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
  3.         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;
  4.         xmlns:src="clr-namespace:Bindingtoclasses"
  5.         Title="MainWindow" Height="350" Width="525">
  6.     <Grid DataContext="{Binding Path=EmployeeName}">
  7.         <Grid.Resources>
  8.                 <src:Employee x:Key="myDataSource" EmployeeName="Kishore1021"/>
  9.         </Grid.Resources>
  10.         <Grid.RowDefinitions>
  11.             <RowDefinition Height="*"></RowDefinition>
  12.             <RowDefinition Height="*"></RowDefinition>
  13.             <RowDefinition Height="*"></RowDefinition>
  14.             <RowDefinition Height="*"></RowDefinition>
  15.         </Grid.RowDefinitions>
  16.         <TextBox Grid.Row="0" Text="{Binding Source={StaticResource myDataSource}, Path=EmployeeName, UpdateSourceTrigger=PropertyChanged}"/>
  17.         <TextBox Grid.Row="1" Text="{Binding Source= {StaticResource myDataSource}, Path=EmployeeName}"></TextBox>
  18.         <TextBox Grid.Row="2" Text="{Binding Path=.}"></TextBox>
  19.         <TextBlock Grid.Row="3" Text="{Binding}"></TextBlock>
  20.             
  21.         </Grid>
  22. </Window>

Points to learn from the above XAML code:

  • Optionally, a period (.) path can be used to bind to the current source. For example, Text="{Binding}" is equivalent to Text="{Binding Path=.}", so line 18 is equal to line 19 in terms of binding. As long as the binding already has a data context (for instance, the inherited data context coming from a parent element), and whatever item or collection being returned by that context is appropriate for binding without requiring further path modification, a binding declaration can have no clauses at all: {Binding}

You can download the source code from here.

MSDN: Use the Path property to specify the source value you want to bind to:

  • In the simplest case, the Path property value is the name of the property of the source object to use for the binding, such as Path=PropertyName.

  • Subproperties of a property can be specified by a similar syntax as in C#. For instance, the clause Path=ShoppingCart.Order sets the binding to the subproperty Order of the object or property ShoppingCart.

  • To bind to an attached property, place parentheses around the attached property. For example, to bind to the attached property DockPanel.Dock, the syntax is Path=(DockPanel.Dock).

  • Indexers of a property can be specified within square brackets following the property name where the indexer is applied. For instance, the clause Path=ShoppingCart[0] sets the binding to the index that corresponds to how your property’s internal indexing handles the literal string "0". Nested indexers are also supported.

  • Indexers and subproperties can be mixed in a Path clause; for example, Path=ShoppingCart.ShippingInfo[MailingAddress,Street].

  • Inside indexers you can have multiple indexer parameters separated by commas (,). The type of each parameter can be specified with parentheses. For example, you can have Path="[(sys:Int32)42,(sys:Int32)24]", where sys is mapped to the System namespace.

  • When the source is a collection view, the current item can be specified with a slash (/). For example, the clause Path=/ sets the binding to the current item in the view. When the source is a collection, this syntax specifies the current item of the default collection view.

  • Property names and slashes can be combined to traverse properties that are collections. For example, Path=/Offices/ManagerName specifies the current item of the source collection, which contains an Offices property that is also a collection. Its current item is an object that contains a ManagerName property.

  • Optionally, a period (.) path can be used to bind to the current source. For example, Text="{Binding}" is equivalent to Text="{Binding Path=.}".

Escaping Mechanism
  • Inside indexers ([ ]), the caret character (^) escapes the next character.

  • If you set Path in XAML, you also need to escape (using XML entities) certain characters that are special to the XML language definition:

    • Use &amp; to escape the character "&".

    • Use &gt; to escape the end tag ">".

  • Additionally, if you describe the entire binding in an attribute using the markup extension syntax, you need to escape (using backslash \) characters that are special to the WPF markup extension parser:

    • Backslash (\) is the escape character itself.

    • The equal sign (=) separates property name from property value.

    • Comma (,) separates properties.

    • The right curly brace (}) is the end of a markup extension.

Default Behaviors

The default behavior is as follows if not specified in the declaration.

  • A default converter is created that tries to do a type conversion between the binding source value and the binding target value. If a conversion cannot be made, the default converter returns null.

  • If you do not set ConverterCulture, the binding engine uses the Language property of the binding target object. In XAML, this defaults to "en-US" or inherits the value from the root element (or any element) of the page, if one has been explicitly set.

  • As long as the binding already has a data context (for instance, the inherited data context coming from a parent element), and whatever item or collection being returned by that context is appropriate for binding without requiring further path modification, a binding declaration can have no clauses at all: {Binding} This is often the way a binding is specified for data styling, where the binding acts upon a collection. For more information, see the "Entire Objects Used as a Binding Source" section in the Binding Sources Overview.

  • The default Mode varies between one-way and two-way depending on the dependency property that is being bound. You can always declare the binding mode explicitly to ensure that your binding has the desired behavior. In general, user-editable control properties, such as TextBox.Text and RangeBase.Value, default to two-way bindings, whereas most other properties default to one-way bindings.

  • The default UpdateSourceTrigger value varies between PropertyChanged and LostFocus depending on the bound dependency property as well. The default value for most dependency properties is PropertyChanged, while the TextBox.Text property has a default value of LostFocus.